You need Bun installed to use this package.
A simple, flexible, and powerful HTTP server based on Bun and Hono. It provides sane defaults to be run in production, while also providing a flexible configuration to be used in development.
- Streaming HTTP responses from file read to response stream
- Static file serving with optional compression and caching
- In-memory cache for responses
- Automatic directory listing for missing files
- SPA mode for single-page applications
- Automatic port selection
- In-memory cache
- Etag
- Compression
- Directory Listings
- SPA Mode
- Automatic TLS
Either install the package globally:
# Install globally
bun add -g @uninspired/unserved
# Run the server
unservedOr run it directly:
# Run the server directly
bunx @uninspired/unservedUnserved can be configured through a configuration file, CLI arguments, or environment variables.
Configuration is read in the following order:
- Environment variables
- Configuration file
- CLI arguments
- Defaults
Each will override the previous one.
You can pass the configuration file path as a CLI argument:
# Run the server with a specific configuration file
unserved --server-config-path ./config.tomlThe following options are also supported:
unserved --help
Options:
--help Show help [boolean]
--version Show version number [boolean]
--server-development Enable development mode [boolean]
--server-port Server port number [string]
--server-hostname Server hostname [string]
--server-log-enabled Enable server logging [boolean]
--server-autoport-enabled Enable automatic port selection [boolean]
--server-serve-hidden-files Serve hidden files [boolean]
--server-secure-headers-enabled Enable secure headers [boolean]
--server-config-path Path to configuration file [string]
--paths-root Root directory path [string]
--paths-base-path Base path for serving files [string]
--paths-spa-mode Enable SPA mode [boolean]
--paths-directory-index Enable directory index [boolean]
--cache-enabled Enable caching [boolean]
--etag-enabled Enable ETag [boolean]
--etag-max-age ETag max age [string]
--compression-enabled Enable compression [boolean]
--compression-mime-types Compression MIME types [string]
--compression-gzip-enabled Enable GZIP compression [boolean]
--compression-gzip-level GZIP compression level [string]
--compression-gzip-mem-level GZIP memory level [string]
--compression-gzip-window-bits GZIP window bits [string]
--compression-brotli-enabled Enable Brotli compression [boolean]
--compression-brotli-quality Brotli compression quality [string]
--compression-deflate-enabled Enable Deflate compression [boolean]
--compression-deflate-level Deflate compression level [string]
--compression-deflate-mem-level Deflate memory level [string]
--compression-deflate-window-bits Deflate window bits [string]The configuration file is a either a unserved.json or unserved.toml file that is located in the current working directory. The path to the configuration file can also be specified through the UNSERVED_CONFIG_PATH environment variable or the --server-config-path CLI argument.
[server]
port = 3000{
"server": {
"port": 3000
}
}The following options are supported:
interface UnservedConfig {
server: {
port: number;
host: string;
autoport: boolean;
log: boolean;
configPath: string;
development: boolean;
serveHiddenFiles: boolean;
secureHeaders: boolean;
};
paths: {
root: string;
basePath: string;
spaMode: boolean;
directoryIndex: boolean;
};
cache: {
enabled: boolean;
};
etag: {
enabled: boolean;
maxAge: number;
};
compression: {
enabled: boolean;
mimeTypes: string[];
gzip: {
enabled: boolean;
level: number;
memLevel: number;
windowBits: number;
};
deflate: {
enabled: boolean;
level: number;
memLevel: number;
windowBits: number;
};
brotli: {
enabled: boolean;
quality: number;
};
};
cors: {
enabled: boolean;
maxAge: number;
origin: string[];
allowHeaders: string[];
allowMethods: string[];
exposeHeaders: string[];
credentials: boolean;
};
csrf: {
enabled: boolean;
origin: string[];
};
}The following environment variables are supported:
interface Env {
NODE_ENV?: "production" | "development";
SERVER_PORT?: number;
SERVER_HOST?: string;
SERVER_AUTOPORT_ENABLED?: boolean;
SERVER_LOG_ENABLED?: boolean;
SERVER_CONFIG_PATH?: string;
SERVER_DEVELOPMENT?: boolean;
SERVER_SERVE_HIDDEN_FILES?: boolean;
SERVER_SECURE_HEADERS_ENABLED?: boolean;
PATHS_ROOT?: string;
PATHS_SPA_MODE_ENABLED?: boolean;
PATHS_BASE_PATH?: string;
PATHS_DIRECTORY_INDEX_ENABLED?: boolean;
CACHE_ENABLED?: boolean;
ETAG_ENABLED?: boolean;
ETAG_MAX_AGE?: number;
COMPRESSION_ENABLED?: boolean;
COMPRESSION_MIME_TYPES?: string[];
COMPRESSION_GZIP_ENABLED?: boolean;
COMPRESSION_GZIP_LEVEL?: number;
COMPRESSION_GZIP_MEM_LEVEL?: number;
COMPRESSION_GZIP_WINDOW_BITS?: number;
COMPRESSION_BROTLI_ENABLED?: boolean;
COMPRESSION_BROTLI_QUALITY?: number;
COMPRESSION_DEFLATE_ENABLED?: boolean;
COMPRESSION_DEFLATE_LEVEL?: number;
COMPRESSION_DEFLATE_MEM_LEVEL?: number;
COMPRESSION_DEFLATE_WINDOW_BITS?: number;
}The following defaults are used if no configuration is provided:
import type { UnservedConfig } from "./config";
export const defaults: UnservedConfig = {
server: {
development: false,
port: 3000,
publicUrl: undefined,
serveHiddenFiles: false,
hostname: "localhost",
secureHeaders: true,
log: true,
autoport: true,
configPath: process.cwd(),
},
paths: {
root: process.cwd(),
basePath: "/",
spaMode: false,
directoryIndex: false,
},
cache: {
enabled: true,
},
etag: {
enabled: true,
maxAge: 60 * 60 * 24, // 1 day
},
compression: {
enabled: true,
mimeTypes: ["text/*", "script/*", "font/*", "image/icon", "image/svg+xml"],
gzip: {
enabled: true,
level: 9,
memLevel: 8,
windowBits: 15,
},
brotli: {
enabled: true,
quality: 11,
},
deflate: {
enabled: true,
level: 9,
memLevel: 8,
windowBits: 15,
},
},
cors: {
enabled: false,
origin: [],
allowHeaders: [],
allowMethods: [],
exposeHeaders: [],
credentials: false,
maxAge: 60 * 60 * 24, // 1 day
},
csrf: {
enabled: false,
origin: [],
},
};