Connecting
Establish and manage connections to SurrealDB with authentication, named connections, and environment-based configuration.
This page covers how to establish and manage connections between your application and SurrealDB.
Basic Connection
import { CerialClient } from './db-client';
const client = new CerialClient();
await client.connect({
url: 'http://localhost:8000',
namespace: 'main',
database: 'main',
auth: { username: 'root', password: 'root' },
});
// Ready to query
const users = await client.db.User.findMany();The connect() method establishes a connection to SurrealDB, authenticates with the provided credentials, and selects the namespace and database.
Connection Options
| Option | Type | Description |
|---|---|---|
url | string | SurrealDB server URL (HTTP or WebSocket) |
namespace | string | SurrealDB namespace to use |
database | string | SurrealDB database within the namespace |
auth | { username: string; password: string } | Authentication credentials |
URL Format
The url option accepts both HTTP and WebSocket URLs. The SurrealDB JavaScript SDK handles the protocol upgrade internally:
// HTTP — SDK upgrades to WebSocket automatically
await client.connect({ url: 'http://localhost:8000', ... });
// HTTPS for production
await client.connect({ url: 'https://db.example.com', ... });Namespace and Database
SurrealDB organizes data in a hierarchy: namespace > database > table. You must specify both a namespace and database when connecting:
await client.connect({
url: 'http://localhost:8000',
namespace: 'production',
database: 'myapp',
auth: { username: 'root', password: 'root' },
});Authentication
Cerial supports root-level authentication with username and password:
await client.connect({
url: 'http://localhost:8000',
namespace: 'main',
database: 'main',
auth: {
username: 'root',
password: 'root',
},
});Disconnecting
Always disconnect when you're done to cleanly close the connection:
await client.disconnect();This is especially important in:
- Server shutdown hooks — ensure connections close on process exit
- Test teardown — clean up after each test suite
- Serverless functions — close connections before the function completes
// Express/Koa shutdown example
process.on('SIGTERM', async () => {
await client.disconnect();
process.exit(0);
});
// Test teardown example
afterAll(async () => {
await client.disconnect();
});Named Connections
You can manage multiple connections by providing a name to connect() and disconnect():
// Connect to multiple databases
await client.connect(
{
url: 'http://localhost:8000',
namespace: 'main',
database: 'primary',
auth: { username: 'root', password: 'root' },
},
'primary',
);
await client.connect(
{
url: 'http://localhost:8000',
namespace: 'main',
database: 'analytics',
auth: { username: 'root', password: 'root' },
},
'secondary',
);
// Disconnect a specific connection
await client.disconnect('secondary');
// Disconnect all connections
await client.disconnectAll();This is useful when your application reads from or writes to multiple databases.
Accessing the Raw Surreal Instance
If you need to perform operations that Cerial doesn't cover, you can access the underlying SurrealDB SDK instance directly:
const surreal = client.getSurreal();
// Run raw SurrealQL queries
const result = await surreal.query(
'SELECT * FROM user WHERE age > $age',
{ age: 25 },
);
// Use any SurrealDB SDK method
await surreal.let('currentUser', userId);This is an escape hatch for advanced use cases. Prefer the typed client.db proxy for normal operations, since it provides type safety and handles record ID transformations automatically.
Connection Patterns
Application Singleton
For most applications, create a single client instance and share it:
// db.ts
import { CerialClient } from './db-client';
export const client = new CerialClient();
export async function initDatabase() {
await client.connect({
url: process.env.SURREAL_URL ?? 'http://localhost:8000',
namespace: process.env.SURREAL_NS ?? 'main',
database: process.env.SURREAL_DB ?? 'main',
auth: {
username: process.env.SURREAL_USER ?? 'root',
password: process.env.SURREAL_PASS ?? 'root',
},
});
}
// app.ts
import { client, initDatabase } from './db';
await initDatabase();
const users = await client.db.User.findMany();Test Setup
For tests, connect in a setup hook and disconnect in teardown:
import { CerialClient } from './db-client';
const client = new CerialClient();
beforeAll(async () => {
await client.connect({
url: 'http://127.0.0.1:8000',
namespace: 'main',
database: 'main',
auth: { username: 'root', password: 'root' },
});
});
afterAll(async () => {
await client.disconnect();
});
test('creates a user', async () => {
const user = await client.db.User.create({
data: { name: 'Alice', email: 'alice@example.com' },
});
expect(user.name).toBe('Alice');
});Atomic Transactions
Use $transaction to execute multiple queries atomically:
const [user, profile] = await client.$transaction([
client.db.User.create({
data: { name: 'Alice', email: 'alice@example.com' },
}),
client.db.Profile.create({
data: { bio: 'Hello world', userId: existingUserId },
}),
]);
// Both created atomically — if either fails, neither is committedEnvironment-Based Configuration
Use environment variables to configure connections per environment:
const config = {
url: process.env.SURREAL_URL!,
namespace: process.env.SURREAL_NS!,
database: process.env.SURREAL_DB!,
auth: {
username: process.env.SURREAL_USER!,
password: process.env.SURREAL_PASS!,
},
};
await client.connect(config);WebSocket for Transactions
Transactions require a WebSocket connection to SurrealDB. If you connect via HTTP, Cerial automatically creates a secondary WebSocket connection for transaction support. No extra configuration needed.
You can control the HTTP connection independently: closeHttp() drops the HTTP connection, reopenHttp() restores it. The WebSocket connection is always kept alive.