This document provides a comprehensive reference for all AshTypescript configuration options.
Application Configuration
Configure AshTypescript in your config/config.exs file:
# config/config.exs
config :ash_typescript,
# Manifest module (required — see "Manifest Module" below)
manifest: MyApp.AshTypescriptManifest,
# File generation (multi-file architecture)
output_file: "assets/js/ash_rpc.ts", # Required for RPC generation (skipped when unset)
types_output_file: nil, # Auto-derives as ash_types.ts in output_file dir
zod_output_file: nil, # Auto-derives as ash_zod.ts in output_file dir
valibot_output_file: nil, # Auto-derives as ash_valibot.ts in output_file dir
# RPC endpoints
run_endpoint: "/rpc/run",
validate_endpoint: "/rpc/validate",
# Field formatting
input_field_formatter: :camel_case,
output_field_formatter: :camel_case,
# Multitenancy
require_tenant_parameters: false,
# Validation schema generation
generate_zod_schemas: false,
zod_import_path: "zod",
zod_schema_suffix: "ZodSchema",
generate_valibot_schemas: false,
valibot_import_path: "valibot",
valibot_schema_suffix: "ValibotSchema",
# Validation functions
generate_validation_functions: false,
# Phoenix channel-based RPC actions
generate_phx_channel_rpc_actions: false,
phoenix_import_path: "phoenix",
# Custom type imports
import_into_generated: [],
# Type mapping overrides
type_mapping_overrides: [],
# Validation-schema overrides for hand-rolled custom types
zod_mapping_overrides: [],
valibot_mapping_overrides: [],
# Extra imports for the generated schema files, so an override above can
# name a schema you authored in TypeScript
zod_import_into_generated: [],
valibot_import_into_generated: [],
# TypeScript type for untyped maps
untyped_map_type: "Record<string, any>",
# RPC resource warnings
warn_on_missing_rpc_config: true,
warn_on_non_rpc_references: true,
# Typed channel warnings
warn_on_non_public_publications: true,
warn_on_missing_channel_returns: true,
# RPC namespace files
enable_namespace_files: false, # Generate separate files for namespaced RPC actions
namespace_output_dir: nil, # Directory for RPC namespace files (defaults to output_file dir)
# Typed channel event subscriptions
typed_channels: [],
typed_channels_output_file: nil,
# Typed controllers
typed_controllers: [],
router: nil,
routes_output_file: nil,
typed_controller_mode: :full,
typed_controller_path_params_style: :object,
typed_controller_base_path: "", # Base URL prefix for all generated route URLs
enable_controller_namespace_files: false, # Generate separate files for namespaced routes
controller_namespace_output_dir: nil, # Directory for controller namespace files
# Typed controller lifecycle hooks
typed_controller_before_request_hook: nil,
typed_controller_after_request_hook: nil,
typed_controller_hook_context_type: "Record<string, any>",
typed_controller_import_into_generated: [],
# Typed controller error handling
typed_controller_error_handler: nil,
typed_controller_show_raised_errors: false,
# Dev codegen behavior
always_regenerate: false,
# Get action behavior
not_found_error?: true,
# Developer experience - JSDoc
add_ash_internals_to_jsdoc: false,
source_path_prefix: nil,
# Developer experience - Manifest
manifest_file: nil,
add_ash_internals_to_manifest: false,
# Machine-readable JSON manifest (for third-party integrations)
json_manifest_file: nil,
json_manifest_filename_format: :relative,
# Error output
policies: [show_policy_breakdowns?: false]Multi-File Output
AshTypescript generates multiple TypeScript files, each with a specific responsibility:
| File | Config Key | Default | Contents |
|---|---|---|---|
| RPC functions | output_file | — (required for RPC generation; the installer sets assets/js/ash_rpc.ts) | RPC functions, hook types, helpers |
| Shared types | types_output_file | Auto-derived as ash_types.ts | Type aliases, resource schemas, filter types, utility types |
| Shared Zod schemas | zod_output_file | Auto-derived as ash_zod.ts | Zod schemas for all resources, RPC actions, and typed controller routes (when generate_zod_schemas: true) |
| Shared Valibot schemas | valibot_output_file | Auto-derived as ash_valibot.ts | Valibot schemas for all resources, RPC actions, and typed controller routes (when generate_valibot_schemas: true) |
| Route helpers | routes_output_file | Auto-derived as ash_routes.ts | Path helpers, typed fetch functions, controller input types (generated when typed_controllers is non-empty) |
| Typed channel functions | typed_channels_output_file | nil (disabled) | Channel factory, subscription helpers, cleanup functions |
| RPC namespace re-exports | namespace_output_dir | Same dir as output_file | Per-namespace re-export files (when enable_namespace_files: true) |
| Controller namespace re-exports | controller_namespace_output_dir | Same dir as routes_output_file | Per-namespace re-export files (when enable_controller_namespace_files: true) |
types_output_file, zod_output_file, and valibot_output_file auto-derive from the output_file directory — set output_file and the others follow. Override individually if needed.
Quick Reference
| Option | Type | Default | Description |
|---|---|---|---|
manifest | module | — (required) | App-wide manifest module (use AshTypescript.Manifest); codegen and runtime raise if unset |
output_file | string | nil | nil | Path for the RPC functions file; when unset, RPC file generation is skipped (the installer sets "assets/js/ash_rpc.ts") |
types_output_file | string | nil | nil | Path for shared types file (auto-derives from output_file dir as ash_types.ts) |
zod_output_file | string | nil | nil | Path for shared Zod schemas file (auto-derives from output_file dir as ash_zod.ts) |
valibot_output_file | string | nil | nil | Path for shared Valibot schemas file (auto-derives from output_file dir as ash_valibot.ts) |
run_endpoint | string | {:runtime_expr, string} | "/rpc/run" | Endpoint for executing RPC actions |
validate_endpoint | string | {:runtime_expr, string} | "/rpc/validate" | Endpoint for validating RPC requests |
input_field_formatter | :camel_case | :pascal_case | :snake_case | {module, function} | {module, function, args} | :camel_case | How to format field names in request inputs |
output_field_formatter | :camel_case | :pascal_case | :snake_case | {module, function} | {module, function, args} | :camel_case | How to format field names in response outputs |
require_tenant_parameters | boolean | false | Whether to require tenant parameters in RPC calls |
generate_zod_schemas | boolean | false | Whether to generate Zod validation schemas |
zod_import_path | string | "zod" | Import path for Zod library |
zod_schema_suffix | string | "ZodSchema" | Suffix for generated Zod schema names |
generate_valibot_schemas | boolean | false | Whether to generate Valibot validation schemas |
valibot_import_path | string | "valibot" | Import path for Valibot library |
valibot_schema_suffix | string | "ValibotSchema" | Suffix for generated Valibot schema names |
generate_validation_functions | boolean | false | Whether to generate form validation functions |
generate_phx_channel_rpc_actions | boolean | false | Whether to generate Phoenix channel-based RPC functions |
phoenix_import_path | string | "phoenix" | Import path for Phoenix library |
import_into_generated | list | [] | List of custom modules to import |
type_mapping_overrides | list | [] | Override TypeScript types for Ash types |
zod_mapping_overrides | list | [] | Override generated Zod schemas for custom Ash types |
valibot_mapping_overrides | list | [] | Override generated Valibot schemas for custom Ash types |
zod_import_into_generated | list | [] | Extra imports for the generated Zod schema file |
valibot_import_into_generated | list | [] | Extra imports for the generated Valibot schema file |
untyped_map_type | string | "Record<string, any>" | TypeScript type for untyped maps |
warn_on_missing_rpc_config | boolean | true | Warn about resources with extension not in RPC config |
warn_on_non_rpc_references | boolean | true | Warn about non-RPC resources referenced by RPC resources |
warn_on_non_public_publications | boolean | true | Warn about typed channel publications not marked public?: true |
warn_on_missing_channel_returns | boolean | true | Warn about typed channel publications with no returns type |
enable_namespace_files | boolean | false | Generate separate files for namespaced RPC actions |
namespace_output_dir | string | nil | nil | Directory for RPC namespace files (defaults to output_file dir) |
typed_channels | list(module) | [] | TypedChannel modules to generate event subscription helpers for |
typed_channels_output_file | string | nil | nil | Output file for typed channel functions (when nil, generation is skipped) |
typed_controllers | list(module) | [] | TypedController modules to generate route helpers for |
router | module | nil | nil | Phoenix router module for path introspection |
routes_output_file | string | Auto-derived as ash_routes.ts in output_file dir | Output file path for generated route helpers |
typed_controller_mode | :full | :paths_only | :full | Generation mode: :full generates path helpers + fetch functions, :paths_only generates only path helpers |
typed_controller_path_params_style | :object | :args | :object | Path parameter style in generated functions |
typed_controller_base_path | string | {:runtime_expr, string} | "" | Base URL prefix for all generated route URLs |
enable_controller_namespace_files | boolean | false | Generate separate files for namespaced controller routes |
controller_namespace_output_dir | string | nil | nil | Directory for controller namespace files (defaults to routes_output_file dir) |
typed_controller_before_request_hook | string | nil | nil | Function called before typed controller requests |
typed_controller_after_request_hook | string | nil | nil | Function called after typed controller requests |
typed_controller_hook_context_type | string | "Record<string, any>" | TypeScript type for typed controller hook context |
typed_controller_import_into_generated | list(map) | [] | Custom imports for generated routes file |
typed_controller_error_handler | mfa | module | nil | nil | Custom error transformation handler |
typed_controller_show_raised_errors | boolean | false | Show exception messages and unexpected handler return values in 500 responses |
always_regenerate | boolean | false | With --dev --check (dev plug), write files directly instead of raising PendingCodegen |
not_found_error? | boolean | true | Global default: true returns error on not found, false returns null |
add_ash_internals_to_jsdoc | boolean | false | Show Ash resource/action details in JSDoc |
source_path_prefix | string | nil | nil | Prefix for source file paths (monorepos) |
manifest_file | string | nil | nil | Path to generate Markdown manifest |
add_ash_internals_to_manifest | boolean | false | Show Ash details in manifest |
json_manifest_file | string | nil | nil | Path to generate a machine-readable JSON manifest for third-party integrations |
json_manifest_filename_format | :relative | :absolute | :basename | :relative | Format of the filename field in JSON manifest files entries |
policies | keyword | [] | show_policy_breakdowns?: true includes the Ash policy breakdown in forbidden-error messages (default: plain "forbidden") |
Lifecycle Hook Configuration
| Option | Type | Default | Description |
|---|---|---|---|
rpc_action_before_request_hook | string | nil | nil | Function called before RPC action requests |
rpc_action_after_request_hook | string | nil | nil | Function called after RPC action requests |
rpc_validation_before_request_hook | string | nil | nil | Function called before validation requests |
rpc_validation_after_request_hook | string | nil | nil | Function called after validation requests |
rpc_action_hook_context_type | string | "Record<string, any>" | TypeScript type for action hook context |
rpc_validation_hook_context_type | string | "Record<string, any>" | TypeScript type for validation hook context |
rpc_action_before_channel_push_hook | string | nil | nil | Function called before channel push for actions |
rpc_action_after_channel_response_hook | string | nil | nil | Function called after channel response for actions |
rpc_validation_before_channel_push_hook | string | nil | nil | Function called before channel push for validations |
rpc_validation_after_channel_response_hook | string | nil | nil | Function called after channel response for validations |
rpc_action_channel_hook_context_type | string | "Record<string, any>" | TypeScript type for channel action hook context |
rpc_validation_channel_hook_context_type | string | "Record<string, any>" | TypeScript type for channel validation hook context |
typed_controller_before_request_hook | string | nil | nil | Function called before typed controller requests |
typed_controller_after_request_hook | string | nil | nil | Function called after typed controller requests |
typed_controller_hook_context_type | string | "Record<string, any>" | TypeScript type for typed controller hook context |
See Lifecycle Hooks and Typed Controllers for complete documentation.
Manifest Module (Required)
AshTypescript builds a single, app-wide Ash.Info.Manifest at compile time — the source of truth that both codegen and the runtime RPC pipeline read from. This manifest lives in a small module you declare in your app, registered via the manifest config key. Codegen and the pipeline raise if manifest is not configured.
# lib/my_app/ash_typescript_manifest.ex
defmodule MyApp.AshTypescriptManifest do
use AshTypescript.Manifest, otp_app: :my_app
end
# config/config.exs
config :ash_typescript, manifest: MyApp.AshTypescriptManifestBy default the module walks Ash.Info.domains(otp_app) to find every domain with a typescript_rpc block, merges them into one spec, and verifies the RPC configuration at compile time. Editing a resource or domain recompiles the manifest automatically, so incremental codegen never goes stale.
For scoped manifests — e.g. building from a freshly-defined domain in a test — pass an explicit domains: list instead of otp_app::
defmodule MyTest.ScopedManifest do
use AshTypescript.Manifest,
otp_app: :my_app,
domains: [MyTest.InlineDomain]
endThe
mix igniter.install ash_typescriptinstaller creates this module and sets the config automatically. You only need to do this by hand for manual installs or when upgrading a project that predates the manifest module.
Domain Configuration
Configure RPC actions and typed queries in your domain modules:
defmodule MyApp.Domain do
use Ash.Domain, extensions: [AshTypescript.Rpc]
typescript_rpc do
resource MyApp.Todo do
# Standard CRUD actions
rpc_action :list_todos, :read
rpc_action :get_todo, :get
rpc_action :create_todo, :create
rpc_action :update_todo, :update
rpc_action :destroy_todo, :destroy
# RPC action options
rpc_action :list_limited, :read, allowed_loads: [:user]
rpc_action :list_no_filter, :read, enable_filter?: false
rpc_action :list_no_sort, :read, enable_sort?: false
# Typed queries for SSR
typed_query :dashboard_todos, :read do
ts_result_type_name "DashboardTodo"
ts_fields_const_name "dashboardTodoFields"
fields [:id, :title, :priority, %{user: [:name]}]
end
end
end
endRPC Action Options
| Option | Type | Default | Description |
|---|---|---|---|
allowed_loads | list(atom | keyword) | nil | Whitelist of loadable fields |
denied_loads | list(atom | keyword) | nil | Blacklist of loadable fields |
enable_filter? | boolean | true | Enable client-side filtering |
enable_sort? | boolean | true | Enable client-side sorting |
get? | boolean | false | Return single record |
get_by | list(atom) | nil | Fields for single-record lookup |
not_found_error? | boolean | nil | Override global not_found_error? |
identities | list(atom) | [:_primary_key] | Allowed identity lookups |
show_metadata | list(atom) | false | nil | nil | Metadata fields to expose |
metadata_field_names | keyword | nil | Metadata field name mappings |
See RPC Action Options for complete documentation.
Dynamic RPC Endpoints
For separate frontend projects, use runtime expressions:
config :ash_typescript,
# Environment variables
run_endpoint: {:runtime_expr, "process.env.RPC_RUN_ENDPOINT || '/rpc/run'"},
# Vite environment variables
# run_endpoint: {:runtime_expr, "import.meta.env.VITE_RPC_RUN_ENDPOINT || '/rpc/run'"},
# Custom functions
# run_endpoint: {:runtime_expr, "MyAppConfig.getRunEndpoint()"}RPC Resource Warnings
AshTypescript provides compile-time warnings for configuration issues:
Missing RPC Configuration Warning
Appears when resources have AshTypescript.Resource extension but are not in any typescript_rpc block.
Non-RPC References Warning
Appears when RPC resources reference other resources that are not configured as RPC resources.
To disable warnings:
config :ash_typescript,
warn_on_missing_rpc_config: false,
warn_on_non_rpc_references: falseTyped Channel Warnings
During typed channel verification, AshTypescript warns about publications that produce lower-quality TypeScript types. Each warning is independently toggleable (default true), mirroring the RPC resource warnings.
Non-Public Publication Warning
Appears when a publication referenced by a typed_channel is not marked public?: true.
Missing Channel Returns Warning
Appears when a publication referenced by a typed_channel has no returns type, so its TypeScript payload type falls back to unknown.
To disable warnings:
config :ash_typescript,
warn_on_non_public_publications: false,
warn_on_missing_channel_returns: falseAlways Regenerate Mode
By default, mix ash_typescript.codegen --check compares the generated output against existing files and raises Ash.Error.Framework.PendingCodegen if they differ. This is useful for CI but in development—especially when using AshPhoenix.Plug.CheckCodegenStatus—you may want to skip the diff check and always write the generated files.
# config/dev.exs
config :ash_typescript, always_regenerate: trueWhen enabled, --dev --check (which AshPhoenix.Plug.CheckCodegenStatus passes automatically in development) writes files directly instead of comparing, so the PendingCodegen error page is never shown during development. Plain --check without --dev (the CI invocation) still raises regardless of this setting.
Typed Channel Configuration
Configure typed channels to generate TypeScript event subscription helpers from Ash PubSub publications. Both typed_channels and typed_channels_output_file must be configured for generation to run.
config :ash_typescript,
typed_channels: [MyApp.OrgChannel, MyApp.ActivityChannel],
typed_channels_output_file: "assets/js/ash_typed_channels.ts"| Option | Type | Default | Description |
|---|---|---|---|
typed_channels | list(module) | [] | Modules using AshTypescript.TypedChannel |
typed_channels_output_file | string | nil | nil | Output file for channel functions (when nil, generation is skipped) |
Channel types (branded types, payload aliases, event maps) are appended to the shared types file (ash_types.ts). Channel functions (factory, subscription helpers) go into typed_channels_output_file and import their types from ash_types.ts.
See Typed Channels for complete documentation.
Typed Controller Configuration
Configure typed controllers to generate TypeScript path helpers and typed fetch functions for Phoenix controller routes. Route generation runs when typed_controllers is non-empty; router is required for path introspection, and routes_output_file auto-derives as ash_routes.ts in the output_file directory when not set explicitly.
config :ash_typescript,
# List of TypedController modules
typed_controllers: [MyApp.Session],
# Phoenix router for path introspection
router: MyAppWeb.Router,
# Output file for generated route helpers
routes_output_file: "assets/js/routes.ts",
# Generation mode (optional)
typed_controller_mode: :full, # :full (default) or :paths_only
typed_controller_path_params_style: :object, # :object (default) or :args
typed_controller_base_path: "", # Base URL prefix (string or {:runtime_expr, "..."})
# Namespace files (optional)
enable_controller_namespace_files: false, # Generate separate files per namespace
controller_namespace_output_dir: nil, # Directory for namespace files (defaults to routes_output_file dir)
# Lifecycle hooks (optional)
typed_controller_before_request_hook: "RouteHooks.beforeRequest",
typed_controller_after_request_hook: "RouteHooks.afterRequest",
typed_controller_hook_context_type: "RouteHooks.RouteHookContext",
typed_controller_import_into_generated: [
%{import_name: "RouteHooks", file: "./routeHooks"}
],
# Error handling (optional)
typed_controller_error_handler: {MyApp.ErrorHandler, :handle, []},
typed_controller_show_raised_errors: false # true only in dev| Option | Type | Default | Description |
|---|---|---|---|
typed_controllers | list(module) | [] | Modules using AshTypescript.TypedController |
router | module | nil | Phoenix router for path introspection |
routes_output_file | string | Auto-derived as ash_routes.ts | Output file path for route helpers |
typed_controller_mode | :full | :paths_only | :full | :full generates path helpers + fetch functions; :paths_only generates only path helpers |
typed_controller_path_params_style | :object | :args | :object | Path parameter style in generated TypeScript |
typed_controller_base_path | string | {:runtime_expr, string} | "" | Base URL prefix for all generated route URLs |
enable_controller_namespace_files | boolean | false | Generate separate files for namespaced routes |
controller_namespace_output_dir | string | nil | nil | Directory for namespace files (defaults to routes_output_file dir) |
typed_controller_before_request_hook | string | nil | nil | Function called before typed controller requests |
typed_controller_after_request_hook | string | nil | nil | Function called after typed controller requests |
typed_controller_hook_context_type | string | "Record<string, any>" | TypeScript type for hook context |
typed_controller_import_into_generated | list(map) | [] | Custom imports (%{import_name: "Name", file: "./path"}) |
typed_controller_error_handler | mfa | module | nil | nil | Custom error transformation handler |
typed_controller_show_raised_errors | boolean | false | Show exception messages and unexpected handler return values in 500 responses |
See Typed Controllers for complete documentation.
Detailed Documentation
For in-depth configuration guides, see:
- Custom Types - Custom Ash types with TypeScript integration
- Field Name Mapping - Mapping invalid field names
- Developer Experience - Namespaces, JSDoc, and manifest generation
- Lifecycle Hooks - HTTP and channel lifecycle hooks
- Phoenix Channels - Channel-based RPC configuration
- Typed Channels - Typed event subscriptions from PubSub
- Multitenancy - Tenant parameter configuration
- Form Validation - Zod and Valibot schema configuration
- Typed Controllers - Controller route helpers
See Also
- Installation - Initial setup
- Mix Tasks Reference - Code generation commands
- Troubleshooting Reference - Common problems and solutions