createApp()

The main factory function. Creates and configures a SpaceNode application with auto-discovery.

import { createApp } from 'SpaceNode'

const app = await createApp(config)

Configuration Options

OptionTypeDefaultDescription
baseUrlstringundefinedimport.meta.url of the entry file — resolves relative paths from that file's directory. Optional for local development (node app.js); recommended for serverless (Vercel, AWS Lambda) and test runners where process.argv[1] may not point to your file
modulesDirstring'./modules'Path to modules folder (relative to entry script or absolute)
staticstring | booleanundefinedPath to static files folder. true auto-detects './public'
spabooleantrueSPA fallback — serve index.html for unmatched GET routes
dbanynullDatabase reference (accessible as request.db)
debugbooleanfalseEnable debug mode — sets logger to 'debug' level, enables EventBus debug logging, includes stack traces in error responses, shows detailed startup banner
recursivebooleanfalseEnable recursive module discovery in nested directories
timeoutnumber30000Server request timeout in ms
keepAliveTimeoutnumber5000Keep-alive timeout in ms
shutdownTimeoutnumber5000Graceful shutdown grace period in ms
pipestring[][]Global pipes applied to ALL routes
bodyLimitnumber1048576Maximum request body size in bytes (default 1MB)
openapiobject | boolean{}OpenAPI spec config (title, version, description, servers). Set to false to disable
wsOriginsstring | string[]nullAllowed WebSocket origins for validation ('*' to allow all)
staticCacheMaxnumber500Max static files to cache in memory
staticCacheFileSizenumber262144Max individual file size to cache (bytes, default 256KB)
loggerobject{}Logger config: { level, transport, timestamps }
trustProxybooleanfalseTrust X-Forwarded-For header for IP resolution (enable behind reverse proxy)
watchbooleanfalseAuto-restart server on file changes (org mode only, like nodemon)

Examples

Minimal

const app = await createApp()
app.listen(3000)

With Database

import mongoose from 'mongoose'
await mongoose.connect('mongodb://localhost/mydb')

const app = await createApp({
  db: mongoose.connection,
  debug: true,
})
app.listen(3000)

With Static Files (SPA)

const app = await createApp({
  static: './public',     // serve static files
  // spa: true,            // SPA fallback (on by default)
})
app.listen(4000)

With Global Pipes

const app = await createApp({
  pipe: ['cors', 'logger', 'rateLimit:100'],  // every route gets these
})
app.listen(3000)

org Mode (Watch)

const app = await createApp({
  watch: true,  // auto-restart on file changes (like nodemon)
})
app.listen(3000)

When watch: true, SpaceNode spawns the server as a child process and watches the working directory for file changes. On any change, it restarts the server automatically. node_modules/ and .git/ are ignored. Zero performance overhead — the watcher runs in a separate process.

org only — don't use watch: true in production. Use a process manager (PM2, Docker, systemd) instead.

App Properties

After creation, the app instance exposes these read-only properties:

PropertyTypeDescription
app.eventsEventBusEvent bus instance — app.events.on(), .emit(), .off()
app.containerContainerDI container — access registered services directly
app.routerRouterTrie router instance — direct access for advanced use cases
app.configobjectMerged configuration object
app.dbanyDatabase reference (from config or setDb())
app.debugbooleanWhether debug mode is enabled

App Methods

MethodDescription
app.listen(port, cb?)Start the HTTP server on the given port
app.close(cb?)Gracefully shut down the server (runs onDestroy hooks)
app.setDb(db)Set/change the database reference
app.setAuth(verifier)Set per-app auth verifier (takes precedence over global defineAuth())
app.addGuard(name, factory)Register a per-app named guard (takes precedence over global defineGuard())
app.setRateLimitStore(store)Set a custom rate limit store (for Redis, etc.)
app.setBodyParser(parser)Set a custom body parser (e.g. busboy, formidable)
app.addModule(definition)Add a module programmatically (without file system)
app.onError(fn)Register a global error handler
app.info()Get app info (modules, routes, services, events)
app.setRoute(method, path, handler, pipes?)Register a route imperatively (without modules)
app.inject(opts)Simulate an HTTP request for testing (no server needed)
app.ws(path, handler)Register a WebSocket handler for a path
app.handle(req, res)Raw request handler for serverless platforms

Path Resolution

All relative paths in config (modulesDir, static) are resolved from the entry script's directory (process.argv[1] — the file you run with node app.js). This works out of the box for local development:

// Just works — paths resolve from the file you run with `node app.js`
const app = await createApp()
app.listen(3000)

Serverless & Production

On serverless platforms (Vercel, AWS Lambda) and in test runners, process.argv[1] points to the platform's bootstrap runtime — not your file. Use baseUrl to resolve paths reliably:

const app = await createApp({
  baseUrl: import.meta.url,  // resolve paths from this file, not process.argv[1]
})

export default (req, res) => app.handle(req, res)
When do you need baseUrl?
  • Local node app.js — not needed, works automatically
  • Serverless (Vercel, Lambda) — required, process.argv[1] is unreliable
  • Test runners (Jest, Vitest) — recommended, process.argv[1] points to the runner
  • Bundled apps — recommended, paths may be rewritten