# Dependencies in TypeScript

> How do I manage TypeScript dependencies in Windmill using Bun and Deno?

In Windmill [standard mode](#lockfile-per-script-inferred-from-imports-standard), dependencies in [TypeScript](../../getting_started/0_scripts_quickstart/1_typescript_quickstart/index.mdx) are handled directly within their scripts without the need to manage separate dependency files.
For TypeScript, there are two runtime options available: [Bun](https://bun.sh/) and [Deno](https://deno.land/).
Both of these runtimes allow you to include dependencies directly in the script, and Windmill automatically handles the resolution and caching of these dependencies to ensure fast and consistent execution (this is standard mode).

There are however methods to have more control on your dependencies:

- Using [workspace dependencies](../../core_concepts/55_workspace_dependencies/index.mdx) for centralized dependency management at the workspace level.
- Leveraging [standard mode](#lockfile-per-script-inferred-from-imports-standard), from the [web IDE or locally](../6_imports/index.mdx#lockfile-per-script-inferred-from-imports-standard).
- [Bundling](#bundle-per-script-built-by-cli) per script with CLI, more powerful and local only.

Moreover, there are other tricks, compatible with the methodologies mentioned above:

- [Sharing common logic with Relative Imports](#sharing-common-logic-with-relative-imports-when-not-using-bundles) when not using Bundles.
- [Private npm registry & private npm packages](#private-npm-registry--private-npm-packages).

To learn more about how dependencies from other languages are handled, see [Dependency management & imports](../../advanced/6_imports/index.mdx).

## Lockfile per script inferred from imports (Standard)

In Windmill, you can run scripts without having to manage dependency files directly. This is achieved by automatically parsing the imports and resolving the dependencies. For more control, you can use [workspace dependencies](../../core_concepts/55_workspace_dependencies/index.mdx).

When using Bun as the runtime for TypeScript in Windmill, dependencies are resolved directly from the script imports and their imports when using [sharing common logic](../5_sharing_common_logic/index.mdx). The TypeScript runtime Bun ensures 100% compatibility with Node.js without requiring any code modifications.

```ts
// unpinned import

// versioned import

```

Similarly, for TypeScript scripts using Deno as the runtime, the dependencies and their versions are specified directly in the script, and the resolution is managed by Deno. This method allows for direct use of npm imports and Windmill client imports without requiring any additional configuration for dependency management.

```ts
// unpinned import

// versioned import

```

Whether deployed from the Web IDE (where the lockfile is recomputed at each deployment by a dependency job) or from the CLI (where each script gets a content file, a metadata file and a lockfile managed with [`wmill generate-metadata`](../3_cli/generate-metadata.md)), the lockfile generation mechanism is the same for all languages and is described in [Dependency management & imports](../6_imports/index.mdx#lockfile-per-script-inferred-from-imports-standard).

## Bundle per script built by CLI

This method can only be deployed from the [CLI](../3_cli/index.mdx), on [local development](../4_local_development/index.mdx).

To work with large custom codebases, there is another mode of deployment that relies on the same mechanism as similar services like Lambda or cloud functions: a bundle is built locally by the CLI using [esbuild](https://esbuild.github.io/) and deployed to Windmill.

This bundle contains all the code and dependencies needed to run the script.

Windmill CLI, it is done automatically on `wmill sync push` for any script that falls in the patterns of includes and excludes as defined by the [wmill.yaml](../../core_concepts/33_codebases_and_bundles/index.mdx#wmillyaml) (in the codebase field).

## Other

Two tricks can be used: [Relative Imports](#sharing-common-logic-with-relative-imports-when-not-using-bundles) and [Private npm registry & private npm packages](#private-npm-registry--private-npm-packages). Both are compatible with the methods described above.

### Sharing common logic with relative imports when not using bundles

If you want to share common logic with Relative Imports when not using [Bundles](#bundle-per-script-built-by-cli), this can be done easily using [relative imports](../5_sharing_common_logic/index.mdx) in both Bun and Deno.

This applies for all methods above, except absolute imports do not work for [codebases and bundles](#bundle-per-script-built-by-cli).

Note that in both the webeditor and with the CLI, your scripts do not necessarily need to have a main function. If they don't, they are assumed to be shared logic and not runnable scripts.

It works extremely well in combination with [Developing scripts locally](../4_local_development/index.mdx) and you can easily sync your scripts with the [CLI](../3_cli/index.mdx).

It is possible to import directly from other TypeScript scripts. One can simply follow the path layout. For instance,
`import { foo } from "./script_name.ts"`. A more verbose example below:

```typescript

```

Relative imports syntax is much preferred as it will work on [local editors](../4_local_development/index.mdx) without further configuration.

In TypeScript Bun, you can drop the .ts extension so:

```typescript

```

would work too.

You may also use absolute imports:

```typescript

	util();
}
```

For these to resolve in your local editor, [`wmill init`](../4_local_development/index.mdx#project-files-generated-by-wmill-init) (or `wmill refresh tsconfig`) generates the needed configuration: a wmill-managed `tsconfig.wmill.json` that maps `/f/` and `/u/` to your local script folders, plus a `tsconfig.json` that extends it. For Deno projects it generates an `import_map.wmill.json` wired through `deno.json` instead. The generated `tsconfig.wmill.json` contains:

```json
{
	"compilerOptions": {
		"paths": {
			"/f/*": ["./f/*"],
			"/u/*": ["./u/*"]
		}
	}
}
```

Note that path in Windmill can have as many depth as needed, so you can have paths like this `f/folder/subfolder/my_script_path.ts` and relative imports will work at any level. Hence, it will work exactly the same as on local.

### Private npm registry & private npm packages

Private registry configuration is an [Enterprise Edition](/pricing) feature.

You can use private npm registries and private npm packages in your TypeScript scripts.

This applies to all methods above. Only, if using Codebases & bundles locally, there is nothing to configure in Windmill, because the bundle is built locally using your locally-installed modules (which support traditional npm packages and private npm packages).

![Private NPM registry](../6_imports/private_registry.png 'Private NPM registry')

#### Using `.npmrc` (recommended)

On [Enterprise Edition](/pricing), go to [Instance settings](../18_instance_settings/index.mdx#registries) -> Registries -> `.npmrc`.

Provide the full content of a standard `.npmrc` file. This works natively with Bun (since 1.1.18), Deno (2.x), and the Windmill npm proxy (which parses the default registry and auth token from the `.npmrc`).

Example `.npmrc` content:

```ini
//npm.pkg.github.com/:_authToken=ghp_xxxxxxxxxxxx
@myorg:registry=https://npm.pkg.github.com/myorg
```

When the `.npmrc` setting is configured, the legacy `Npm config registry` and `Bunfig install scopes` fields are hidden for new setups.

#### Using registry URL (legacy)

Alternatively, set the registry URL directly in [Instance settings](../18_instance_settings/index.mdx#registries) -> `Npm config registry`: `https://npm.pkg.github.com/OWNER` (replace `OWNER` with your GitHub username or organization name).

Currently, Deno does not support private npm packages requiring tokens (but support private npm registries). Bun however does.

If a token is required, append `:_authToken=<your token>` to the URL (replace `<your token>` with your actual token).

Combining the two, you can import private packages from npm

```
https://registry.npmjs.org/:_authToken=npm_YOUR_TOKEN_HERE
```

If the private registry is exposing custom certificates,`DENO_CERT` and `DENO_TLS_CA_STORE` env variables can be used as well (see [Deno documentation](https://docs.deno.com/runtime/manual/getting_started/setup_your_environment#environment-variables) for more info on those options).

```dockerfile
windmill_worker:
  ...
  environment:
    ...
    - DENO_CERT=/custom-certs/root-ca.crt
```
