Skip to main content

Configuration

There's both codegen and runtime configuration of the ent framework.

codegen

codegen can be configured in a yml file in order of precedence (from the root of the project):

  • a ent.yml file
  • a src/ent.yml file
  • a src/graphql/ent.yml file

The root of codegen configuration is the codegen key in the file.

The following properties can be configured:

  • defaultEntPolicy configures the Privacy Policy in base class of generated Ents. Overrides the default privacy policy. See PrivacyConfig for the expected format.
  • defaultActionPolicy configures the Privacy Policy in base class of generated Actions. Overrides the default privacy policy. See PrivacyConfig for the expected format.
  • Biome is the default formatter for generated TypeScript. Codegen will use the project's biome.json or biome.jsonc when present, and otherwise fall back to ent's bundled Biome config.
  • prettier configures legacy Prettier formatting and makes codegen use Prettier instead of Biome. See PrettierConfig for the expected format.
  • relativeImports configures where to use relative imports in generated files instead of src/ent/user etc. needed for legacy scenarios or situations where the custom compiler has issues.
  • disableGraphQLRoot: the default graphql root is src/graphql/index.ts. if integrating into an existing project (with an existing root) or just want to do something different, set this to true
  • generatedHeader: add header to each generated file in addition to "Generated by github.com/lolopinto/ent, DO NOT EDIT."
  • disableBase64Encoding: disable base64encoding of id fields. When set to true, id fields aren't resolved with nodeIDEncoder and the actual uuid or integer is sent to the client
  • generateRootResolvers: for each type exposed to GraphQL instead of node(). Should be used in combination with
  • defaultGraphQLMutationName: default names for graphql actions|mutations is nounVerb e.g. userCreate. If you wanna change it to verbNoun e.g. createUser, set this field to VERB_NOUN
  • defaultGraphQLFieldFormat: default format for fields is lowerCamelCase e.g. firstName. If you wanna change it to snake_case e.g. first_name, set this field to snake_case
  • schemaSQLFilePath: if we should generate schema.sql file and path to generate it
  • globalImportPath: path to add to src/ent/internal.ts so that it's included everywhere. Where things like global augmentation can be done
  • userOverridenFiles: list of files to not override during codegen i.e. because there's a bug in codegen and the user has decided to override it.
  • transformLoadMethod: if set, overrides the loadNoTransform(X) methods to be this instead of the default loadNoTransform(X)
  • transformDeleteMethod: if set, overrides the saveWithoutTransform(X) methods to be this instead of the default saveWithoutTransform(X)
  • disableDefaultExportForActions: by default, actions are exported with export default. This changes that to named defaults.

PrivacyConfig

Following fields supported:

  • policyName (string. required). name of default privacy policy
  • path (string. required). path to import to get the policy
  • class (boolean. optional). indicates if the policy is a class as opposed to a constant.

PrettierConfig

Following fields supported:

  • custom (boolean. optional). indicates there's already a custom prettier configuration that should be used.
  • glob (string. optional). glob to pass to prettier instead of default src/**/*.ts

Formatting

Generated TypeScript is formatted with Biome during codegen unless codegen.prettier is configured or --force_prettier is passed.

Codegen looks for biome.json or biome.jsonc at the project root and lets Biome apply that configuration directly. If neither file exists, ent falls back to its bundled Biome config. Formatter options are no longer copied into .ent/schema.json; the Biome config file is the source of truth.

To preserve single quotes or other project formatting preferences, add a project-root biome.json or biome.jsonc:

biome.json
{
"javascript": {
"formatter": {
"quoteStyle": "single",
"jsxQuoteStyle": "single"
}
}
}

runtime

Because there could be so many possible entrypoints into the framework e.g. GraphQL endpoint, REST API endpoint, tests, migration script, etc, there's no way to automatically configure runtime behavior so it has to be done manually via calling loadConfig.

loadConfig

loadConfig takes an optional file, Buffer or Config. If nothing is passed, it assumes local ent.yml file, if string is passed, it assumes yml file and attempts to read and parse it.

loadConfig(file?: string | Buffer | Config | ConfigWithCodegen): void;

type logType = "query" | "warn" | "info" | "error" | "debug";

export interface Database {
database?: string;
user?: string;
password?: string;
host?: string;
port?: number;
ssl?: boolean;
sslmode?: string;
}

export type env = "production" | "test" | "development";
export declare type DBDict = Partial<Record<env, Database>>;

export interface Config {
dbConnectionString?: string; // raw db connection string
dbFile?: string; // config/database.yml is default
db?: Database | DBDict;
log?: logType | logType[]; // logging levels.

// dev branch schemas (postgres only)
devSchema?: RuntimeDevSchemaConfig;

// optional runtime extension validation / schema overrides
extensions?: RuntimeDBExtension[];
}

export interface ConfigWithCodegen extends Config {
// config for codegen. not relevant when loadConfig is called but accepted when reading ent.yml
codegen?: CodegenConfig;

// codegen/tooling extends the runtime config with prune support
devSchema?: DevSchemaConfig;
}

interface CodegenConfig {
defaultEntPolicy?: PrivacyConfig;
defaultActionPolicy?: PrivacyConfig;
// legacy Prettier formatting. prefer biome.json or biome.jsonc at the project root
prettier?: PrettierConfig;
}

interface PrettierConfig {
custom?: boolean;
// default glob is 'src/**/*.ts', can override this
glob?: string;
}

interface PrivacyConfig {
path: string; // e.g. "@snowtop/ent"
policyName: string; // e.g. "AlwaysAllowPrivacyPolicy";
class?: boolean;
}

interface RuntimeDevSchemaConfig {
enabled?: boolean;
schemaName?: string; // optional explicit schema name
includePublic?: boolean;
ignoreBranches?: string[];
}

interface RuntimeDBExtension {
name: string;
provisionedBy?: "ent" | "external";
version?: string;
installSchema?: string;
runtimeSchemas?: string[];
dropCascade?: boolean;
}

interface DevSchemaConfig extends RuntimeDevSchemaConfig {
prune?: {
enabled?: boolean;
days?: number; // default 30
};
}

Example

ent.yml
log:
- query
- error
- warn
- info
codegen:
defaultEntPolicy:
path: "@snowtop/ent"
policyName: "AlwaysAllowPrivacyPolicy"
defaultActionPolicy:
path: "@snowtop/ent"
policyName: "AlwaysAllowPrivacyPolicy"
prettier:
custom: true
devSchema:
enabled: true
# includePublic: false
# ignoreBranches:
# - main
# - master
prune:
enabled: true
days: 30

Dev branch schemas (postgres only)

When devSchema.enabled is true (and NODE_ENV is not production), ent will derive a per-branch postgres schema and set search_path automatically. The schema name is based on the git branch name unless schemaName is explicitly provided (explicit names are sanitized and will be prefixed with schema_ if they start with a digit). Note that schemaName does not enable dev schemas by itself; devSchema.enabled must be set to true. This feature is not supported for sqlite and will error if enabled with a sqlite connection.

If you pass devSchema to runtime loadConfig, that config is self-sufficient: ent derives the schema directly from the current git branch unless schemaName is explicitly provided. It does not require src/schema/.ent/dev_schema.json.

If runtime config is not provided, ent falls back to src/schema/.ent/dev_schema.json, which is written by Go codegen. In that state-file mode, ent fails closed if the current branch cannot be determined or does not match the stored branchName. After switching branches, rerun tsent codegen before using the generated state again.

By default, the dev schema is isolated (includePublic defaults to false). Set includePublic: true to add public to the search_path for reads while still keeping reflection/compare limited to the dev schema.

If you want to disable dev schemas on certain branches (e.g. main/master), set devSchema.ignoreBranches. This applies unless you force-enable via ENT_DEV_SCHEMA_ENABLED=true.

devSchema.prune is a codegen/tooling setting, not a TS runtime setting. It is used when writing the generated state file and by tsent prune_schemas. Runtime loadConfig does not prune schemas on connection open.

You can force-enable or disable this behavior with ENT_DEV_SCHEMA_ENABLED (useful for tests).

DB extensions at runtime

Extension packages such as @snowtop/ent-postgis and @snowtop/ent-pgvector register their type parsers and default runtime schemas when they are imported. Ent batches those registrations into a single type lookup query at startup, so multiple extensions do not each issue their own pg_type query.

If you want fail-fast runtime validation, version checks, or non-default runtime schemas, pass extensions to loadConfig:

import { loadConfig } from "@snowtop/ent";
import { PostGISExtension } from "@snowtop/ent-postgis";

loadConfig({
dbConnectionString: process.env.DB_CONNECTION_STRING,
extensions: [
PostGISExtension(),
],
});

provisionedBy has the same meaning here as in dbExtensions:

  • "ent" is the default. It means Ent owns the extension lifecycle in migrations.
  • "external" means the database service or DBA owns the extension lifecycle and Ent should only validate that it already exists.

Runtime config is optional when the package defaults are enough. It is recommended when:

  • you want startup to fail if a required extension is missing or at the wrong version
  • the extension is installed outside public
  • dev-schema mode needs extra schemas added to search_path