---
schema_version: "1"
id: 67851c7d91f4ed73f84da821c38a80b83acc4a533cef6dd3cb290ddfd45bbef7
title: Scope Visibility in DataWeave
collection: mulesoft
version: current
locale: en-us
portal_url: https://docs.salesforce.com/mulesoft/current/en-us/dataweave/2.12/dataweave-scope-visibility.md
canonical_url: https://docs.mulesoft.com/dataweave/2.12/dataweave-scope-visibility
source_site: docs.mulesoft.com
content_type: documentation
content_hash: d317ee3b44cfc23b149a5cec06ba7c18da131fac781b3d13f16309ce25834ac4
description: MuleSoft Documentation Site
release: "2.12"
latest: false
---
---
product: DataWeave
version: 2.12
---

# Scope Visibility in DataWeave

> For the full documentation index, see: https://docs.mulesoft.com/llms.txt

DataWeave 2.12.0 introduces scope visibility so you can control which directives in a DataWeave file
are accessible from other files. Visibility rules apply to module-level declarations: `fun`, `var`,
`type`, `ns`, and `annotation`.

Scope visibility is primarily for DataWeave library authors. If you write Mule transformation
mappings (the `%dw 2.0` script in a Transform Message component), you can ignore this feature
because a mapping is a single, self-contained file that doesn’t export directives to other files.
Visibility becomes relevant when you publish a `.jar` that other DataWeave code imports.

## Visibility Levels

DataWeave 2.12.0 supports three visibility levels:

<table><colgroup><col> <col> <col></colgroup><thead><tr><th>Level</th><th>Keyword</th><th>Accessible From</th></tr></thead><tbody><tr><td><p>Public</p></td><td><p><em>(none)</em></p></td><td><p>Anywhere. Default and only behavior in versions before 2.12.0.</p></td></tr><tr><td><p>Private</p></td><td><p><code>private</code></p></td><td><p>The same file only.</p></td></tr><tr><td><p>Internal</p></td><td><p><code>internal</code></p></td><td><p>Any file in the same <a href="#components">component</a>. Can be widened with <code>@VisibleTo</code>.</p></td></tr></tbody></table>

> [!NOTE] Visibility checks run only at compile time. Once a script is compiled, no runtime
> visibility check is performed. This keeps execution overhead at zero and ensures pre-compiled
> (`.bdwl`) modules behave the same as source modules.

## Syntax

Place the visibility keyword before the directive keyword (`fun`, `var`, `type`, `ns`, and
`annotation`).

```dataweave
%dw 2.0

// Public (default) — accessible from anywhere
fun greet(name: String) = "Hello, $(name)!"

// Private — accessible only inside this file
private fun normalize(name: String) = upper(name)

// Internal — accessible from any file in the same component
internal var defaultGreeting = "Hello"

// Type and namespace declarations also support visibility
private type UserName = String
internal ns http https://schemas.example.org/http
```

The `@VisibleTo` annotation widens an `internal` directive to a fixed list of additional components:

```dataweave
%dw 2.0
import * from dw::Core

@VisibleTo(components = ["analytics", "reporting"])
internal fun computeStats(records: Array) = sizeOf(records)
```

`@VisibleTo` is only valid on `internal` directives. Applying it to a `private` directive or to a
directive without a visibility keyword raises a compile-time error:
`The @VisibleTo annotation can only be applied to 'internal' directives`.

## What Is a Component?

DataWeave doesn’t provide a `module` or `package` keyword to group files. Until 2.12.0, every `.dwl`
file lived in one global namespace. To make `internal` meaningful, the language now uses the
component concept, which is a named set of DataWeave resources (modules) that are compiled and
packaged together.

A component is described by a component descriptor, a `.dwl` resource located at
`META-INF/dw-components.dwl` inside a `.jar` file. The descriptor is an array of components, and
each component lists the resources it owns:

```dataweave
%dw 2.0
---
[
    {
        name: "wlang",
        resources: {
            "dw::Core": {},
            "dw::Crypto": {},
            "dw::core::Arrays": {},
            "dw::core::Strings": {}
            // ...
        }
    }
]
```

When the compiler resolves a reference to a symbol declared in another module, it consults the
descriptors on the classpath to determine the components that own the declaring module and the
caller module.

### Generating the Descriptor

You don’t write the descriptor manually. The [Maven plugin for DataWeave](https://docs.mulesoft.com/dataweave/2.12/dataweave-maven-plugin)
generates it automatically:

- For a production build (`data-weave:package`), the plugin scans `src/main/dw`, derives the
  resource names of every `.dwl` file, and writes
  `target/generated-dataweave-metadata/dw-components.dwl`. The file is added to the produced JAR at
  `META-INF/dw-components.dwl`.

- For a test build (`data-weave:test`), the plugin scans both `src/main/dw` and `src/test/dw`, so
  test files belong to the same component as the production sources they exercise. This lets tests
  call `internal` directives without further configuration.

The component name defaults to the Maven `artifactId` of the project.

### Component Resolution Algorithm

Given a reference from caller `A` to symbol `s` declared in module `B`, the compiler looks up
`componentOf(B)` from the descriptors on the classpath. Access is allowed based on the visibility of
`s`:

- If `s` is `private`, access is allowed only when `A == B`.

- If `s` is `internal`, access is allowed when `componentOf(A) == componentOf(B)`, or when
  `componentOf(A)` appears in the `@VisibleTo` list on `s`.

- If `s` is `public`, access is always allowed.

If a module declares `internal` directives and no descriptor on the classpath claims it, the
compiler emits the `Module 'X' declares 'internal' members but has no component descriptor` error.
In that case, package the module with the Maven plugin for DataWeave or add a component descriptor
that lists it.

## Compile-Time Validation

The compiler reports four new errors:

<table><colgroup><col> <col></colgroup><thead><tr><th>Error Kind</th><th>Triggered When</th></tr></thead><tbody><tr><td><p><code>PrivateAccessViolation</code></p></td><td><p>A reference targets a <code>private</code> directive declared in a different file.</p></td></tr><tr><td><p><code>InternalAccessViolation</code></p></td><td><p>A reference targets an <code>internal</code> directive declared in a different component, when the caller’s component isn’t in the directive’s <code>@VisibleTo</code> list.</p></td></tr><tr><td><p><code>VisibleToRequiresInternal</code></p></td><td><p><code>@VisibleTo</code> is applied to a directive that isn’t <code>internal</code>.</p></td></tr><tr><td><p><code>MissingComponentForInternalDirective</code></p></td><td><p>A module declares <code>internal</code> directives but no component descriptor on the classpath claims it.</p></td></tr></tbody></table>

## Function Overloads and Visibility

Function overloads must use the same visibility. Mixing `internal fun foo(x: String) = …​` and
`fun foo(x: Number) = …​` is rejected with an error that indicates the expected visibility (from the
first overload). This guarantees that callers see a single, consistent visibility for any given
function name.

## Structural Types and Visibility Propagation

DataWeave uses a structural type system. Visibility on a type controls who can reference the type by
name and doesn’t propagate to functions or variables that use that type in their signature. A caller
can invoke a function whose signature mentions a `private` type as long as the caller doesn’t name
that type.

```dataweave
// In component A
private type Account = { id: String }

@VisibleTo(components = ["bat"])
internal fun createAccount(account: Account) = account

// In component B (bat)
import createAccount from componentA::Accounts

// OK — structural call, no explicit reference to `Account`
createAccount({ id: "abc" })

// Error — explicit reference to private type `Account`
createAccount({ id: "abc" }) as Account
```

The same rule applies to type annotations on variables (`var x: Account = …​`) and pattern matches
that name a type.

## Examples

These examples demonstrate common visibility patterns for DataWeave library authors.

### File-Local Helper

Use `private` to restrict a helper function to a single file.

```dataweave
// dw/core/Core.dwl

%dw 2.0

private fun isLegacyMode(): Boolean =
    evaluateCompatibilityFlag("com.mulesoft.dw.legacyMode")

fun sizeOf(value) =
    if (isLegacyMode()) legacyImpl(value) else newImpl(value)
```

`isLegacyMode` is reachable only inside `Core.dwl`.

### Component-Internal Helper

Use `internal` to share helper functions across files within the same component while preventing
external access.

```dataweave
// dw/core/Internal.dwl   (component: wlang)
%dw 2.0
internal fun dropFrame(): Boolean = ...

// dw/core/Core.dwl   (component: wlang)
%dw 2.0
import dropFrame from dw::core::Internal
fun process() = if (dropFrame()) ... else ...   // OK — same component

// com/acme/App.dwl   (component: acme-app)
%dw 2.0
import dropFrame from dw::core::Internal         // Error: internal to `wlang`
```

### Sharing Internals With a Specific Component

Use `@VisibleTo` with `internal` to allow specific external components to access a directive.

```dataweave
// dw/native/Native.dwl   (component: wlang)
%dw 2.0

@VisibleTo(components = ["bat", "dataweave-io"])
internal fun nativeImpl() = ...

// bat/core/Runner.dwl   (component: bat)
import nativeImpl from dw::native::Native        // OK — bat is permitted

// com/paypal/Connector.dwl   (component: paypal-connector)
import nativeImpl from dw::native::Native        // Error — not permitted
```

## Migrating From `@Internal(permits=…​)`

In versions before 2.12.0, the only way to constrain visibility was the experimental
`@Internal(permits = […​])` annotation, which matched callers by `NameIdentifier` prefix.
`@Internal` is still accepted in 2.12.0 but is deprecated in favor of the new keywords:

<table><colgroup><col> <col></colgroup><thead><tr><th>Old Form</th><th>Replacement</th></tr></thead><tbody><tr><td><p><code>@Internal(permits = [])</code></p></td><td><p><code>private</code></p></td></tr><tr><td><p><code>@Internal(permits = ["dw::"])</code></p></td><td><p><code>internal</code> (the consuming component must also be migrated to a 2.12.0 build so a descriptor exists)</p></td></tr><tr><td><p><code>@Internal(permits = ["bat::", "dw::"])</code></p></td><td><p><code>@VisibleTo(components = ["bat"])</code> <code>internal</code></p></td></tr></tbody></table>

Files that don’t use any visibility keyword behave exactly as in earlier versions: every directive
is public.

## Setting a Per-Component Language Level

When a host application embeds the DataWeave engine, it can pin a specific language level for each
component using the new `componentLanguageLevels` parameter on `DWScriptingEngine.compileDWScript`:

```scala
def compileDWScript(
    script: String,
    languageLevel: String,
    componentLanguageLevels: util.Map[String, String] = new util.HashMap()
): DWScript
```

This is used together with `@Since` on function overloads to dispatch to the correct overload when a
library evolves, ensuring backward compatibility for existing scripts.

## See Also

- [`dw::meta::Component` Module](https://docs.mulesoft.com/dataweave/2.12/dw-component)

- [`@VisibleTo` Annotation](https://docs.mulesoft.com/dataweave/2.12/dw-core-annotations)

- [Maven plugin for DataWeave](https://docs.mulesoft.com/dataweave/2.12/dataweave-maven-plugin)

- [DataWeave extension plugin](https://docs.mulesoft.com/dataweave/2.12/dataweave-extension-plugin)
