Skip to main content
Icon

Project Configuration

Learn about all the ways you can customize your project's build and deployment settings

The OwnStak configuration file (ownstak.config.mjs) allows you to customize how your project is built, deployed and store this config together with your project source code. This file should be placed in your project's root directory. If no file is found, the CLI uses default or auto-detected values.

You can create a new config for your project by running:

npx ownstak config init

This command will launch a wizard to guide you through the setup. Other supported file names include ownstak.config.js, ownstak.config.cjs, and ownstak.config.ts.

Basic Example

Here's a basic example of an Ownstak configuration file:

ownstak.config.mjs
import { Config } from 'ownstak';

export default new Config()
.setOrganization("my-org")
.setProject("my-next-app")
.setRuntime("nodejs22.x")
.setArch("arm64");

The configuration file is evaluated only once at build time, which means you can configure it programmatically or use environment variables from your CI/CD pipelines in it:

ownstak.config.mjs
import { Config } from 'ownstak';

export default new Config().setRuntime(process.env.OWNSTAK_RUNTIME)

Basic Options

setProject

Sets the name of your project (project). This name is later displayed in the OwnStak Console. By default, the project name from package.json is used. If the project doesn't exist in the given organization, the CLI will create it on deploy.

  • Default: Name from package.json or 'default'
  • Type: .setProject(name: string)

setOrganization

Sets the name of your organization (organization) in the OwnStak Console. The organization needs to exist; otherwise, deployment fails.

  • Default: Name from package.json or 'default'
  • Type: .setOrganization(name: string)

setEnvironment

Sets the environment name (environment) for your deployment that is later also displayed in the OwnStak Console. Defaults to default. If the environment doesn't exist in the given organization and project, the CLI will create it on deploy.

  • Default: 'default'
  • Type: .setEnvironment(name: string)

setRuntime

Sets the Node.js runtime version (runtime) to use for your application.

  • Default: Automatically selected based on your local Node.js version
  • Supported Values: 'nodejs18.x', 'nodejs20.x', 'nodejs22.x'
  • Type: .setRuntime(runtime: string)

setMemory

Sets the amount of RAM (memory) in MiB to allocate to your application.

  • Default: 1024
  • Range: 1–10240 MiB
  • Type: .setMemory(sizeInMiB: number)

setArch

Sets the CPU architecture (arch) to use for your application.

  • Default: Automatically selected based on your local architecture
  • Supported Values: 'x86_64', 'arm64'
  • Type: .setArch(architecture: string)

setTimeout

Sets the maximum execution time (timeout) in seconds for your application.

  • Default: 20
  • Range: 1–900 seconds
  • Type: .setTimeout(durationInSeconds: number)

setFramework

Sets the framework (framework) to use for your application. The OwnStak CLI comes with support for predefined frameworks and will auto-detect supported frameworks during the npx ownstak deploy or npx ownstak build commands. If you want to deploy a custom project type, set the framework to custom and see the Custom framework guide.

  • Default: Auto-detected framework
  • Supported Values: 'nextjs', 'astrojs', 'static', 'custom'
  • Type: .setFramework(framework: string)

Advanced Options

includeApp

Includes application files (app) and runtime dependencies. Use this to include or exclude additional files in your build, such as dynamically loaded dependencies, server-side code, or custom config files that your app requires.

  • Type: .includeApp(path: string, destination?: string | boolean)

Examples:

// Include a single file under the same name
.includeApp("my-config.json")

// Include files with glob pattern under the same name
.includeApp("src/**/*.{json,yml}")

// Include files into custom destination
.includeApp("src/**/*.{json}", "dist/**/*")

// Include all files from src folder and exclude only json files
.includeApp("src/**/*")
.includeApp("src/**/*.{json}", false)

includeAsset

Includes static assets (assets) - static files that don't contain a hash in their name and can change between deployments, e.g., index.html. This option is usually configured by the frameworkAdapter. The path can contain files, directories, or glob patterns that are absolute or relative to the project source directory. The destination defines the target destination inside the build directory. Use true to include the asset under the same path as the source, false to exclude it, or define a custom path as a string.

  • Type: .includeAsset(path, destination?)

Examples:

// Include a single file under the same name
.includeAsset("index.html")

// Include entire directory into custom destination
.includeAsset("./public", "./")

// Include files with glob patterns
.includeAsset("dist/**/*.{html,css,js}")

// Include with custom destination
.includeAsset("src/assets", "public/assets")

// Include all files in public folder and exclude just files in the public/temp/ folder
.includeAsset("public/**/*")
.includeAsset("public/temp/**/*", false)

includePermanentAsset

Includes permanent static assets (permanentAssets) - files that contain a content hash in their name and are expected to never change, e.g., chunk-asdf123.js. This option is usually configured by the frameworkAdapter. It uses the same syntax format as includeAsset.

  • Type: .includePermanentAsset(path, destination?)

includeDebugAsset

Includes debug assets (debugAssets) that are included during development or debugging builds. These assets are typically used for debugging purposes and may include source maps, debug logs, or development-specific files. It uses the same syntax format as includeAsset.

  • Type: .includeDebugAsset(path, destination?)

setAppEntrypoint

Sets the entry point (app.entrypoint) for your application. This entrypoint should start the HTTP server on process.env.PORT with your application. Optionally, the app entrypoint can export a function as the default export that starts the server and returns a promise that resolves when the server is ready to accept requests.

  • Type: .setAppEntrypoint(entrypoint: string)

Examples:

// Basic Express.js server
.setAppEntrypoint("./server.js")

setCopyAppDependencies

Controls whether to trace and copy all your app entrypoint dependencies (app.copyDependencies) during the build. When enabled, OwnStak automatically analyzes your entrypoint file and includes all required dependencies. This includes node_modules, source files, and any files your application imports.

This option saves you time, so you don't need to manually include all required node_modules into the build. You still might need to include all dependencies that your app dynamically reads. For example, config.json files, etc.

  • Default: false
  • Type: .setCopyAppDependencies(value: boolean)

setBundleAppDependencies

Controls whether to bundle all your app entrypoint dependencies (app.bundleDependencies) during the build. The bundling process will include all dependencies into your resulting entrypoint file, which results in faster startup times but may not work for all dependency/app types. The output format (ESM/CJS) is selected based on the input format.

  • Default: false
  • Type: .setBundleAppDependencies(value: boolean)

setAppCompression

Controls whether to apply compression on the uncompressed responses from your app. By default, compression is enabled for all modern browsers/clients that support it and for supported text content-types that are effectively compressible (e.g.: text/html, application/json, image/svg+xml...) and disabled for media content-types (e.g.: image/webp, video/mp4, audio/aac....)

Set this option to false if you would like to disable compression for all responses, for example, to offload the compression to a CDN or proxy server. Be aware that disabling compression will increase your overall bandwidth usage and possibly latency.

  • Default: true
  • Type: .setAppCompression(compression: boolean)
  • Supported algorithms brotli, gzip, deflate

setAppStreaming

Controls the end-to-end HTTP streaming from your app. Set to false (default) to disable streaming and buffer the entire response in memory before sending it to the client. Set to true to stream the response in incremental chunks as it is generated by your app to achieve lower latency and TTFB.

When disabled (false): When streaming is disabled, the full response is buffered in memory until processing is complete, then sent to the client in a single transmission. This is useful for debugging and error handling. Response status code and headers can still be altered even after writing the body. If any error occurs during processing, regardless of phase, the client will receive a proper HTML/JSON 5xx error response. The downside is higher memory usage with increasing response size.

When enabled (true): When streaming is enabled, each written response body chunk is sent directly to the client in increments of up to 32 KiB. Once the first response body chunk is written, the status code and headers can no longer be altered. This is useful for large responses, effective memory usage, and improving Time To First Byte (TTFB) metrics of your app. Error behavior depends on when the error occurs:

  • If the error occurs before response status and headers are sent, the client receives an HTML/JSON 5xx error response (same as when streaming is disabled).
  • If the error occurs after response status and headers are sent, it is too late to alter the status code. The client will instead encounter HTTP2 RST_STREAM, a TCP connection reset, incomplete chunked response, or timeout (depending on your app and the used protocol), indicating the response with 2xx status is incomplete/corrupted and should not be cached. For the end client, this can result in an error page from the browser (e.g., Connection reset by peer) or just a blank page depending on the used browser.
  • Default: false
  • Type: .setAppStreaming(streaming: boolean)

setFrameworkAdapter

Sets the framework adapter (frameworkAdapter) that defines how to build and deploy your application. The CLI comes with predefined adapters for supported frameworks, but this option allows you to write your own support for any framework or tweak the existing behavior by hooking into each build phase.

  • Default: Auto-detected framework adapter
  • Type: .setFrameworkAdapter(adapter: FrameworkAdapter)

setSkipFrameworkBuild

Sets whether to skip the framework build (skipFrameworkBuild) and use existing build output when npx ownstak build or npx ownstak deploy commands are called.

  • Default: false
  • Type: .setSkipFrameworkBuild(skip: boolean = true)

setBuildCommand

Sets the build command (buildCommand) that should be executed during the build process when running npx ownstak build or npx ownstak deploy. This option allows you to customize how your application is built or integrate with your existing build workflow.

For example, set it to npx docusaurus build to build and deploy your documentation site with a single command. OwnStak comes with predefined build commands for supported frameworks. Use this option if you want to use a different build command for your Next.js framework.

  • Default: Framework-specific build command (e.g., npx next build for Next.js) or undefined for custom and static frameworks
  • Type: .setBuildCommand(command: string)

setDevCommand

Sets the dev command (devCommand) that should be executed when running npx ownstak dev to start your development server. This option allows you to customize how your application runs in development mode or integrate with your existing development workflow.

For example, set it to npx docusaurus start to start your documentation site in development mode. OwnStak comes with predefined dev commands for supported frameworks. Use this option if you want to use a different dev command for your Next.js framework.

  • Default: Framework-specific dev command (e.g., npx next dev for Next.js) or undefined for custom and static frameworks
  • Type: .setDevCommand(command: string)

setDefaultFile

Sets the default file (assets.defaultFile or permanentAssets.defaultFile) to serve when no route matches. Set this option to index.html asset if your static SPA app serves the same index.html file for all paths. Set this option to 404.html asset if your static MPA app serves only known paths and 404.html file for everything else.

  • Type: .setDefaultFile(filePath: string)

setDefaultStatus

Sets the default HTTP status code for unmatched routes (for both assets.defaultStatus and permanentAssets.defaultStatus). Set this option to 200 status code if your static SPA app serves the same index.html file for all paths. Set this option to 404 status code if your static MPA app serves only known paths and 404.html file for everything else.

  • Type: .setDefaultStatus(statusCode: number)

setConvertHtmlToFolders

Controls whether to convert all .html files to folder format with index.html inside (for both assets.convertHtmlToFolders and permanentAssets.convertHtmlToFolders). For example, /about.html file will become accessible at /about.

  • Default: false
  • Type: .setConvertHtmlToFolders(value: boolean)

setRedirect

Sets up HTTP redirects for your application. Useful for redirecting old URLs to new ones, maintaining SEO rankings, and ensuring users reach the correct content.

  • Default statusCode: 302
  • Type: .setRedirect(from, to, statusCode?)

Examples:

// Basic redirect (302)
.setRedirect('/old-page', '/new-page')

// Permanent redirect (301)
.setRedirect('/legacy-blog', '/new-blog', 301)

// Redirect with path parameters
.setRedirect('/blog/:slug', '/new-blog/:slug', 301)

// Redirect with wildcard paths
.setRedirect('/docs/v1/:path*', '/docs/v2/:path*', 308)

// Complex condition redirect
.setRedirect({
path: /^\/old-section\/.*$/,
method: 'GET'
}, '/new-section', 301)

setResponseHeaders

Sets custom HTTP response headers for your application. Useful for cache control, security headers, CORS, and other custom headers.

  • Type: .setResponseHeaders(headers, path?)

Examples:

// Set headers for all paths
.setResponseHeaders({
"X-Frame-Options": "DENY",
"X-Content-Type-Options": "nosniff",
"Cache-Control": "public, max-age=31536000"
})

// Set headers for specific paths
.setResponseHeaders({ "Cache-Control": "public, max-age=31536000" }, "/assets/:path*")
.setResponseHeaders({ "Cache-Control": "no-cache" }, {
path: /\.html$/,
method: "GET"
})

setRequestHeaders

Sets custom HTTP request headers to request or overrides existing before it reaches your application code in compute.

  • Type: .setRequestHeaders(headers, path?)

Examples:

// Set headers for all incoming requests
.setRequestHeaders({
"User-Agent": "MyApp/1.0",
"Authorization": "Bearer your-api-key"
})

// Set headers only requests with specific path
.setRequestHeaders({ "X-API-Version": "v2" }, "/api/:path*")
.setRequestHeaders({ "Content-Type": "application/json" }, {
path: /^\/api\/.*$/,
method: "POST"
})

setResponseStatus

Sets the HTTP status code for responses. Primarily used for static sites to control how 404 pages are handled.

  • Default: 200
  • Type: .setResponseStatus(status: number)

setRouter

Sets the internal Router that allows you to define more complex routing logic for your project. This configuration option is not recommended for end-users.

  • Type: .setRouter(router: Router)

Methods Example

The Config provides several methods for programmatically setting configuration values in your own code. Here's an example of all available methods:

ownstak.config.mjs
import { Config } from 'ownstak';

export default new Config()
.setOrganization('my-org')
.setProject('my-app')
.setEnvironment('production')
.setRuntime('nodejs20')
.setMemory(2048)
.setArch('x86_64')
.setTimeout(30)
.setFramework('custom')
.includeAsset('./public', './')
.includePermanentAsset('./static')
.includeDebugAsset('./debug')
.includeApp('./dist/server.js', './server.js')
.setDevCommand('npx vite dev')
.setBuildCommand('npx vite build')
.setAppEntrypoint('./server.js')
.setCopyAppDependencies(true)
.setBundleAppDependencies(true)
.setAppCompression(true)
.setAppStreaming(true)
.setConvertHtmlToFolders(true)
.setSkipFrameworkBuild(true)
.setDefaultStatus(200)
.setDefaultFile('static/index.html')
.setRequestHeaders({ 'User-Agent': 'MyApp/1.0' })
.setResponseHeaders({ 'X-Frame-Options': 'DENY' })
.setRedirect("/old/:path*", "/new/:path*")
.setFrameworkAdapter({
name: 'My custom framework',
hooks: {
'build:start': ({ config }) => {}, // Runs at the beginning of the build process
'build:routes:start': ({ config }) => {}, // Runs before any default routes are added
'build:routes:finish': ({ config }) => {}, // Runs after all routes are added
'build:finish': ({ config }) => {}, // Runs right before build completion
'dev:start': ({ config }) => {} // Runs when starting the development server
}
})
tip

This is the default and recommended way to define your OwnStak project configuration.

Options Example

Here's a complete example showing all available options on Config object:

ownstak.config.js
import { Config } from 'ownstak';

export default new Config({
project: 'my-custom-app',
organization: 'my-org',
environment: 'production',
runtime: 'nodejs20',
memory: 2048,
arch: 'x86_64',
timeout: 30,
framework: 'custom',
skipFrameworkBuild: false,
buildCommand: 'npx vite build',
devCommand: 'npx vite dev',
assets: {
convertHtmlToFolders: true,
defaultFile: 'static/index.html',
defaultStatus: 200,
include: {
'./public': './',
'./static': true,
'./public/*.{js,css}': false
}
},
permanentAssets: {
convertHtmlToFolders: false,
defaultFile: 'static/index.html',
defaultStatus: 200,
include: {
'./_astro': './'
}
},
debugAssets: {
include: {
'./debug': true
}
},
app: {
include: {
'./dist/server.js': './server.js'
},
entrypoint: './server.js',
copyDependencies: false,
bundleDependencies: false,
compression: true,
streaming: true
},
requestHeaders: {
'User-Agent': 'MyApp/1.0',
'Authorization': 'Bearer your-api-key'
},
responseHeaders: {
'X-Frame-Options': 'DENY',
'X-Content-Type-Options': 'nosniff'
},
frameworkAdapter: {
name: 'My custom framework',
hooks: {
'build:start': ({ config }) => {}, // Runs at the beginning of the build process
'build:routes:start': ({ config }) => {}, // Runs before any default routes are added
'build:routes:finish': ({ config }) => {}, // Runs after all routes are added
'build:finish': ({ config }) => {}, // Runs right before build completion
'dev:start': ({ config }) => {} // Runs when starting the development server
}
}
});

JSON Example

If you prefer not to install ownstak as a project dependency or simply want to avoid using JavaScript/TypeScript, you can define the configuration using a plain JSON file:

ownstak.config.json
{
"project": "my-nextjs-app",
"organization": "my-org"
}
note

Environment variables cannot be used with the JSON config.