Configuration file (ende.json)
This page documents the fields you can set in a ende.json (or ende.jsonc)
configuration file. For an overview of how Ende discovers and applies
configuration, see the Configuration
concept page.
Dependencies
The "imports" field in your ende.json allows you to specify dependencies
used in your project. You can use it to map bare specifiers to URLs or file
paths making it easier to manage dependencies and module resolution in your
applications.
For example, if you want to use the assert module from the standard library in
your project, you could use this import map:
{
"imports": {
"@ende/assert": "jsr:@ende/assert@^2026.10.15",
"@ende/fmt": "jsr:@ende/fmt@^2026.10.15"
}
}Then your script can use the bare specifiers @ende/assert and @ende/fmt:
import { assertEquals } from "@ende/assert";
import { yellow } from "@ende/fmt/colors";
assertEquals(1, 2);
console.log(yellow("Hello world"));Read more about module imports and dependencies
Custom path mappings
The import map in ende.json can be used for more general path mapping of
specifiers. You can map an exact specifiers to a third party module or a file
directly, or you can map a part of an import specifier to a directory.
{
"imports": {
// Map to an exact file
"foo": "./some/long/path/foo.ts",
// Map to a directory, usage: "bar/file.ts"
"bar/": "./some/folder/bar/"
}
}Usage:
import * as foo from "foo";
import * as bar from "bar/file.ts";
Path mapping of import specifies is commonly used in larger code bases for brevity.
For example:
{
"imports": {
"@/": "./"
}
}import { MyUtil } from "@/util.ts";This causes import specifiers starting with @/ to be resolved relative to the
import map's URL or file path.
Scoped mappings
The "scopes" field lets you override import mappings for modules loaded from a
particular path prefix, following the
import maps specification.
Each key is a scope (a path prefix), and its value is an import map that applies
only to modules whose specifier falls under that scope. This is useful when two
dependencies need different versions of the same package.
{
"imports": {
"@ende/assert": "jsr:@ende/assert@^2026.10.15"
},
"scopes": {
"./legacy/": {
"@ende/assert": "jsr:@ende/assert@^2026.10.15"
}
}
}In this example modules under ./legacy/ resolve @ende/assert to the older
version, while the rest of the project uses the version from "imports".
Overriding packages
The links field in ende.json allows you to override dependencies with local
packages stored on disk.
{
"links": [
"../some-package"
]
}This capability addresses several common development challenges:
- Dependency bug fixes
- Private local libraries
- Compatibility issues
The package being referenced doesn't need to be published at all. It just needs
to have the proper package name and metadata in ende.json, so that Ende knows
what package it's dealing with. This provides greater flexibility and
modularity, maintaining clean separation between your main code and external
packages.
Tasks
The tasks field in your ende.json file is used to define custom commands
that can be executed with the ende task command and allows you to tailor
commands and permissions to the specific needs of your project.
{
"tasks": {
"start": "ende run --allow-net --watch=static/,routes/,data/ dev.ts",
"test": "ende test --allow-net",
"lint": "ende lint"
}
}To execute a task, use the ende task command followed by the task name. For
example:
ende task start
ende task test
ende task lint
Read more about ende task.
Linting
The lint field in the ende.json file is used to configure the behavior of
Ende’s built-in linter. This allows you to specify which files to include or
exclude from linting, as well as customize the linting rules to suit your
project’s needs.
For example:
{
"lint": {
"include": ["src/"],
"exclude": ["src/testdata/", "src/fixtures/**/*.ts"],
"rules": {
"tags": ["recommended"],
"include": ["ban-untagged-todo"],
"exclude": ["no-unused-vars"]
}
}
}This configuration will:
- only lint files in the
src/directory, - not lint files in the
src/testdata/directory or any TypeScript files in thesrc/fixtures/directory. - specify that the recommended linting rules should be applied,
- add the
ban-untagged-todo, and - exclude the
no-unused-varsrule.
You can find a full list of available linting rules in the List of rules documentation page.
Read more about linting with Ende.
Formatting
The fmt field in the ende.json file is used to configure the behavior of
Ende’s built-in code formatter. This allows you to customize how your code is
formatted, ensuring consistency across your project, making it easier to read
and collaborate on. Here are the key options you can configure:
{
"fmt": {
"useTabs": true,
"lineWidth": 80,
"indentWidth": 4,
"semiColons": true,
"singleQuote": true,
"proseWrap": "preserve",
"include": ["src/"],
"exclude": ["src/testdata/", "src/fixtures/**/*.ts"]
}
}This configuration will:
- use tabs instead of spaces for indentation,
- limit lines to 80 characters,
- use an indentation width of 4 spaces,
- add semicolons to the end of statements,
- use single quotes for strings,
- preserve prose wrapping,
- format files in the
src/directory, - exclude files in the
src/testdata/directory and any TypeScript files in thesrc/fixtures/directory.
The fmt field accepts the following options, each shown with its default and
allowed values:
json.trailingCommas controls trailing commas in JSON and JSONC files
separately from the trailingCommas option, which applies to JavaScript and
TypeScript. The maintain value keeps trailing commas as written, and the
jsonc value adds trailing commas in .jsonc files while omitting them in
.json files.
Read more about formatting your code with Ende.
Lockfile
The lock field in the ende.json file is used to specify configuration of the
lock file that Ende uses to
ensure the integrity of your dependencies.
A lock file records the exact versions and integrity hashes of the modules your
project depends on, ensuring that the same versions are used every time the
project is run, even if the dependencies are updated or changed remotely.
{
"lock": {
"path": "./ende.lock",
"frozen": true
}
}This configuration will:
- specify lockfile location at
./ende.lock(this is the default and can be omitted) - tell Ende that you want to error out if any dependency changes
Ende uses lockfile by default, you can disable it with following configuration:
{
"lock": false
}Merge conflicts
After merging branches, ende.lock can be left with git conflict markers. These
markers make the file invalid JSON, which used to make Ende error out with
Lockfile may be corrupt. Ende now resolves these conflicts for you: the next
command that reads the lockfile merges the conflicting entries and rewrites a
clean file. Most of the lockfile is a set of identity-keyed entries where a key
always maps to the same value regardless of which branch wrote it, so the merge
is a union and you do not need to edit the markers by hand.
Minimum dependency age
The minimumDependencyAge field stops Ende from installing JSR package versions
that were published more recently than the configured age. Freshly published
malicious versions are usually detected and yanked within days, so a small delay
window catches the bulk of supply-chain attacks. See
supply chain management for guidance on
choosing a window.
{
// Don't install versions published less than 3 days ago
"minimumDependencyAge": "P3D"
}The value accepts an
ISO-8601 duration such as
P3D or PT72H, a number of minutes (120), an absolute cutoff date
(2025-09-16) or RFC3339 timestamp, or 0 to disable.
A 24-hour minimum applies by default even when this field is unset; set an
explicit value to widen or narrow the window, or 0 to turn it off.
To exempt specific packages, use the object form with an exclude list:
{
"minimumDependencyAge": {
"age": "P3D",
"exclude": ["jsr:@mycompany/cli", "jsr:@mycompany/lib"]
}
}The same control is available as the --minimum-dependency-age CLI flag.
TypeScript compiler options
The compilerOptions field in the ende.json file is used to configure
TypeScript compiler settings for your
Ende project. This allows you to customize how TypeScript code is compiled,
ensuring it aligns with your project’s requirements and coding standards.
Note
Ende recommends the default TypeScript configuration. This will help when sharing code.
Existing tsconfig.json files work out of the box with Ende. See the
tsconfig.json compatibility reference
for the supported fields and precedence rules.
For the full list of supported compiler options, library configuration, and advanced settings, see Configuring TypeScript.
Unstable features
The unstable field in a ende.json file is used to enable specific unstable
features for your Ende project.
These features are still in development and not yet part of the stable API. By
listing features in the unstable array, you can experiment with and use these
new capabilities before they are officially released.
{
"unstable": ["cron", "webgpu"]
}include and exclude
Many configurations (ex. lint, fmt) have an include and exclude property
for specifying the files to include.
include
Only the paths or patterns specified here will be included.
{
"lint": {
// only format the src/ directory
"include": ["src/"]
}
}
exclude
The paths or patterns specified here will be excluded.
{
"lint": {
// don't lint the dist/ folder
"exclude": ["dist/"]
}
}
This has HIGHER precedence than include and will win over include if a path
is matched in both include and exclude.
You may wish to exclude a directory, but include a sub directory. In Ende 1.41.2+, you may un-exclude a more specific path by specifying a negated glob below the more general exclude:
{
"fmt": {
// don't format the "fixtures" directory,
// but do format "fixtures/scripts"
"exclude": [
"fixtures",
"!fixtures/scripts"
]
}
}
Top level exclude
If there's a directory you never want Ende to fmt, lint, type check, analyze in the LSP, etc., then specify it in the top level exclude array:
{
"exclude": [
// exclude the dist folder from all sub-commands and the LSP
"dist/"
]
}
Sometimes you may find that you want to un-exclude a path or pattern that's excluded in the top level-exclude. You may un-exclude a path by specifying a negated glob in a more specific config:
{
"fmt": {
"exclude": [
// format the dist folder even though it's
// excluded at the top level
"!dist"
]
},
"exclude": [
"dist/"
]
}
Publish - Override .gitignore
The .gitignore is taken into account for the ende publish command. In Ende
1.41.2+, you can opt-out of excluded files ignored in the .gitignore by using
a negated exclude glob:
dist/
.env
{
"publish": {
"exclude": [
// include the .gitignored dist folder
"!dist/"
]
}
}Alternatively, explicitly specifying the gitignored paths in an "include"
works as well:
{
"publish": {
"include": [
"dist/",
"README.md",
"ende.json"
]
}
}
Exports
The exports field in the ende.json file allows you to define which paths of
your package should be publicly accessible. This is particularly useful for
controlling the API surface of your package and ensuring that only the intended
parts of your code are exposed to users.
{
"exports": "./src/mod.ts" // A default entry point
}You can also define multiple entry points:
{
"exports": {
"./module1": "./src/module1.ts",
"./module2": "./src/module2.ts",
".": "./src/mod.ts" // Default entry point
}
}This configuration will:
- expose
module1andmodule2as entry points for your package, and - make
./src/mod.tsthe default entry point (.).
Users can import these modules using the specified paths, while other files in your package remain private.
To use the exports in your code, you can import them like this:
import * as module_1 from "@example/my-package/module1";
import * as module_2 from "@example/my-package/module2";Permissions
Ende supports storing permission sets in the config file.
Named permissions
Permissions can be defined as key-value pairs under arbitrarily-named permission
sets under the "permissions" key. Within each set,
- the key is the name of a permission that
would follow
--allow-or--deny-in the CLI invocation (i.e.read,write,net,env,sys,run,ffi,import) - the value is a boolean (
true/falsecorrespond to allow / deny), an array of strings representing paths, domains etc., or an object withallow,deny, and/orignoreboolean key-value pairs.
{
"permissions": {
"read-data": {
"read": "./data"
},
"read-and-write": {
"read": true,
"write": ["./data"]
}
}
}
Permission sets can be used by specifying the --permission-set=<name> or
-P=<name> flag:
$ ende run -P=read-data main.ts
Default permission
A special "default" permission key allows excluding the name when using the
--permission-set/-P flag:
{
"permissions": {
"default": {
"env": true
}
}
}
Then run with just -P:
$ ende run -P main.ts
Allow, deny, and ignore
For finer control over permissions, you can use the object form with allow,
deny, and ignore keys. This is especially useful when you need more granular
permission control than simple boolean or array values provide.
Object form syntax
Instead of specifying a permission as a boolean or array:
{
"permissions": {
"default": {
"read": true, // Simple boolean form
"write": ["./data"] // Simple array form
}
}
}
You can use the object form:
{
"permissions": {
"default": {
"read": {
"allow": ["./data", "./config"],
"deny": ["./data/secrets"],
"ignore": ["./data/cache"]
},
"write": {
"allow": ["./output"],
"deny": ["./output/system"]
}
}
}
}
Available permissions
The allow, deny, and ignore keys work differently depending on the
permission type:
readandenv: Supportallow,deny, andignorewrite,net,run,ffi,sys, andimport: Supportallowanddeny(but notignore)
Behavior
allow: Explicitly grant access to specific resources. Can betrue(to allow all),false(to allow none), or an array of specific paths/values to allow.deny: Explicitly deny access (throw PermissionDenied) to specific resources, even if they would otherwise be allowed. Can betrue(to deny all),false(to deny none), or an array of specific paths/values to deny.ignore: (Only forreadandenvpermissions) Silently ignore access attempts to specific resources without throwing errors. Can betrue,false, or an array of specific paths/values to ignore.
Example
{
"permissions": {
"default": {
// Allow reading from data directory, but deny access to secrets
// and silently ignore cache files
"read": {
"allow": ["./data"],
"deny": ["./data/secrets"],
"ignore": ["./data/cache"]
},
// Allow all environment variables except API keys
"env": {
"allow": true,
"ignore": ["API_KEY", "SECRET_TOKEN"]
},
// Allow all, but deny 'rm', 'sudo'
"run": {
"allow": true,
"deny": ["rm", "sudo"]
}
}
}
}
Test, bench, and compile permissions
Permissions can be optionally specified within the "test", "bench", or
"compile" keys.
{
"test": {
"permissions": {
"read": ["./data"]
}
}
}
Or reference a permission set:
{
"test": {
"permissions": "read-data"
},
"permissions": {
"read-data": {
"read": ["./data"]
}
}
}
When this is defined, you must run ende test with -P or a permission flag:
> ende test
error: Test permissions were found in the config file. Did you mean to run with `-P`?
at file:///Users/david/dev/example/ende.json
> ende test -P
...runs...
> ende test --allow-read
...runs...
> ende test -A
...runs...
This is to help prevent you waste your time wondering why something is not working when you forget to run without permissions.
Note that test and bench files in a workspace will use the closest ende.json
for determining test and bench permissions. This allows giving different
permissions to different workspace members.
Security risk
The threat model for permissions in the config file is similar to ende task,
in that a script could modify the ende.json to elevate permissions. That's why
this requires an explicit opt-in with -P and is not loaded by default.
If you're ok with this risk, then this feature will be useful for you.
Compile config
The "compile" block configures
ende compile without requiring you to
repeat flags on every invocation. You can declare which extra files or
directories to bundle into the executable, and which paths to exclude:
{
"compile": {
"include": ["names.csv", "data", "worker.ts"],
"exclude": ["data/secrets", "**/*.test.ts"]
}
}--include and --exclude flags on the command line are merged with these
lists rather than replacing them. The "compile" block can also carry
permissions (see
Test, bench, and compile permissions).
An example ende.json file
{
"compilerOptions": {
"allowJs": true,
"lib": ["ende.window"],
"strict": true
},
"permissions": {
"default": {
"read": {
"allow": ["./src/"],
"deny": ["./src/secrets/"]
},
"env": {
"allow": true,
"ignore": ["TEMP_*"]
}
}
},
"lint": {
"include": ["src/"],
"exclude": ["src/testdata/", "src/fixtures/**/*.ts"],
"rules": {
"tags": ["recommended"],
"include": ["ban-untagged-todo"],
"exclude": ["no-unused-vars"]
}
},
"fmt": {
"useTabs": true,
"lineWidth": 80,
"indentWidth": 4,
"semiColons": false,
"singleQuote": true,
"proseWrap": "preserve",
"include": ["src/"],
"exclude": ["src/testdata/", "src/fixtures/**/*.ts"]
},
"lock": false,
"unstable": ["webgpu"],
"test": {
"include": ["src/"],
"exclude": ["src/testdata/", "src/fixtures/**/*.ts"]
},
"tasks": {
"start": "ende run --allow-read main.ts"
},
"imports": {
"@hono/hono": "jsr:@hono/hono@^4"
},
"exclude": [
"dist/"
]
}
This is an example of a ende.json file that configures the TypeScript compiler
options, linter, formatter, etc. For a full list of available fields and
configurations, see the Ende configuration file schema.
JSON schema
A JSON schema file is available for editors to provide autocompletion. The file is versioned and available at: https://github.com/theende/ende/blob/primary/cli/schemas/config-file.v1.json
Proxies
Ende supports proxies for module downloads and the fetch API. Proxy configuration is read from environment variables: HTTP_PROXY, HTTPS_PROXY and NO_PROXY.
If you are using Windows - if environment variables are not found Ende falls back to reading proxies from the registry.