Configuration
Resora can be customized using a project-level configuration file.
By default, Resora works without configuration. However, you may create a resora.config.ts file in your project root to customize behavior.
import { defineConfig } from 'resora';
export default defineConfig({
resourcesDir: 'src/resources',
stubsDir: 'stubs',
stubs: {
resource: 'resource.stub',
collection: 'collection.stub',
},
});For simplicity, Resora ships a CLI tool to help with repetitive tasks. To initialize a config file with safe defaults, run the following command in your project root:
npm run resora initpnpm resora inityarn resora initConfig File Location
Resora looks for a configuration file in your project root in the following order:
resora.config.tsresora.config.jsresora.config.cjs
The first file found will be loaded and merged with the default configuration.
Basic Example
// resora.config.ts
import { defineConfig } from 'resora';
export default defineConfig({
resourcesDir: 'src/http/resources',
stubsDir: 'stubs/resora',
});JavaScript version:
// resora.config.js
module.exports = {
resourcesDir: 'src/http/resources',
stubsDir: 'stubs/resora',
};How Configuration Is Loaded
At runtime:
- Resora loads its internal defaults.
- It checks for a config file in the current working directory.
- If found, the config is deeply merged with the defaults.
- User-defined values override defaults.
Available Configuration Options
resourcesDir - src/resources
Specifies where generated Resource and Collection classes should be stored.
Example
export default defineConfig({
resourcesDir: 'app/transformers',
});All generated files will now be placed inside:
app/transformersstubsDir - Internal Resora stub directory
Specifies the base directory for stub templates used by the CLI generator.
Example
export default defineConfig({
stubsDir: 'stubs',
});Resora will now resolve stub templates from:
stubs/stubs - Default stub file names
Allows overriding specific stub files.
Example
export default defineConfig({
stubs: {
resource: 'resource.stub',
collection: 'collection.stub',
},
});Stub resolution will now look inside:
<stubsDir>/<stub file name>Custom Stub Example
You can fully customize how generated resources look by overriding the stub templates.
Example directory:
stubs/
resource.stub
collection.stubInside resource.stub:
import { Resource } from 'resora'
export default class {{ResourceName}} extends Resource {
data () {
return this.toArray()
}
}The CLI will replace:
{{ResourceName}}{{CollectionResourceName}}{{collects = Resource}}{{import = Resource}}
preferredCase - camel
Controls key casing for serialized resource payloads.
Supported values:
camelsnakepascalkebab- Custom transformer
(key: string) => string
Example
export default defineConfig({
preferredCase: 'snake',
});If your resource returns:
{ "firstName": "John", "lastName": "Doe" }Response payload becomes:
{ "first_name": "John", "last_name": "Doe" }Custom transformer
export default defineConfig({
preferredCase: (key) => key.toUpperCase(),
});responseStructure - { rootKey: 'data', wrap: true }
Customizes the JSON envelope used for serialized responses.
Supported options:
wrap: enable/disable payload wrappingrootKey: rename wrapper key (datatopayload, etc.)factory: fully custom response builder
Disable wrapping
export default defineConfig({
responseStructure: {
wrap: false,
},
});For plain object payloads, the outer data envelope is removed.
When metadata exists on non-object payloads (for example arrays with pagination meta), Resora keeps a wrapped object to preserve meta.
Custom root key
export default defineConfig({
responseStructure: {
rootKey: 'payload',
},
});Response becomes:
{
"payload": { ... }
}Custom response factory
export default defineConfig({
responseStructure: {
factory: (payload, context) => ({
success: true,
type: context.type,
result: payload,
}),
},
});context includes:
type:resource,collection, orgenericrootKey: resolved wrapper keyresource: original input resourcemeta: resolved metadata (if any)
paginatedExtras - ['meta', 'links']
Controls which pagination/cursor blocks are attached at the response root.
You can use:
- an array of built-ins (
meta,links,cursor) - or custom output keys via object syntax.
Example (custom root keys)
export default defineConfig({
paginatedExtras: {
meta: 'meta',
links: 'navigation',
cursor: 'cursor_info',
},
});baseUrl - https://localhost
Base URL used to build absolute pagination link URLs.
pageName - page
Query parameter used when generating pagination links.
Example (link URL generation)
export default defineConfig({
baseUrl: 'https://api.example.com/v1',
pageName: 'p',
});With a resource pagination payload like:
{
"pagination": {
"firstPage": 1,
"nextPage": 3,
"path": "/users"
}
}Generated links become:
{
"links": {
"first": "https://api.example.com/v1/users?p=1",
"next": "https://api.example.com/v1/users?p=3"
}
}paginatedMeta - Default pagination field map
Renames metadata fields emitted for pagination info.
Default source keys:
tofromlinkspathtotalper_pagelast_pagecurrent_page
paginatedLinks - Default link field map
Renames pagination link keys.
Supported source keys:
firstlastprevnext
cursorMeta - { previous: 'previous', next: 'next' }
Renames cursor metadata keys.
Example (cursor mapping)
export default defineConfig({
paginatedExtras: {
meta: 'meta',
cursor: 'cursor',
},
cursorMeta: {
previous: 'before',
next: 'after',
},
});Cursor output becomes:
{
"cursor": {
"before": "cursor_prev",
"after": "cursor_next"
}
}When Configuration Is Useful
Use configuration when:
- You follow a specific folder structure
- You want fully customized resource templates
- You are integrating Resora into a larger framework
- You want consistency across multiple teams
No Configuration Required
If no config file is found:
- Default directories are used
- Default stub templates are used
- CLI generation still works
Resora is zero-config by default, but configurable when needed.