SpaceNode
The main factory function. Creates and configures a SpaceNode application with auto-discovery.
import { createApp } from 'SpaceNode'
const app = await createApp(config)
| Option | Type | Default | Description |
|---|---|---|---|
baseUrl | string | undefined | import.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 |
modulesDir | string | './modules' | Path to modules folder (relative to entry script or absolute) |
static | string | boolean | undefined | Path to static files folder. true auto-detects './public' |
spa | boolean | true | SPA fallback — serve index.html for unmatched GET routes |
db | any | null | Database reference (accessible as request.db) |
debug | boolean | false | Enable debug mode — sets logger to 'debug' level, enables EventBus debug logging, includes stack traces in error responses, shows detailed startup banner |
recursive | boolean | false | Enable recursive module discovery in nested directories |
timeout | number | 30000 | Server request timeout in ms |
keepAliveTimeout | number | 5000 | Keep-alive timeout in ms |
shutdownTimeout | number | 5000 | Graceful shutdown grace period in ms |
pipe | string[] | [] | Global pipes applied to ALL routes |
bodyLimit | number | 1048576 | Maximum request body size in bytes (default 1MB) |
openapi | object | boolean | {} | OpenAPI spec config (title, version, description, servers). Set to false to disable |
wsOrigins | string | string[] | null | Allowed WebSocket origins for validation ('*' to allow all) |
staticCacheMax | number | 500 | Max static files to cache in memory |
staticCacheFileSize | number | 262144 | Max individual file size to cache (bytes, default 256KB) |
logger | object | {} | Logger config: { level, transport, timestamps } |
trustProxy | boolean | false | Trust X-Forwarded-For header for IP resolution (enable behind reverse proxy) |
watch | boolean | false | Auto-restart server on file changes (org mode only, like nodemon) |
const app = await createApp()
app.listen(3000)
import mongoose from 'mongoose'
await mongoose.connect('mongodb://localhost/mydb')
const app = await createApp({
db: mongoose.connection,
debug: true,
})
app.listen(3000)
const app = await createApp({
static: './public', // serve static files
// spa: true, // SPA fallback (on by default)
})
app.listen(4000)
const app = await createApp({
pipe: ['cors', 'logger', 'rateLimit:100'], // every route gets these
})
app.listen(3000)
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.
watch: true in production. Use a process manager (PM2, Docker, systemd) instead.
After creation, the app instance exposes these read-only properties:
| Property | Type | Description |
|---|---|---|
app.events | EventBus | Event bus instance — app.events.on(), .emit(), .off() |
app.container | Container | DI container — access registered services directly |
app.router | Router | Trie router instance — direct access for advanced use cases |
app.config | object | Merged configuration object |
app.db | any | Database reference (from config or setDb()) |
app.debug | boolean | Whether debug mode is enabled |
| Method | Description |
|---|---|
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 |
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)
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)
baseUrl?
node app.js — not needed, works automaticallyprocess.argv[1] is unreliableprocess.argv[1] points to the runner