Before setting up the SDK, ensure you have:
- Completed the CLI wizard
- Obtained an API key from the Tusk Drift dashboard (only required if using Tusk Cloud)
📦 Using Next.js? Next.js applications require a different initialization process. Go to the Next.js Initialization Guide →
For standard Node.js applications (Express, Fastify, plain Node.js, etc.), follow these steps in order to properly initialize the Tusk Drift SDK:
Create a separate file (e.g. tuskDriftInit.ts or tuskDriftInit.js) to initialize the Tusk Drift SDK. This ensures the SDK is initialized as early as possible before any other modules are loaded.
Note: The code examples in this guide use ES module import/export syntax. If your JavaScript project uses CommonJS, adapt the examples to use require()/module.exports instead.
IMPORTANT: Ensure that TuskDrift is initialized before any other telemetry providers (e.g. OpenTelemetry, Sentry, etc.). If not, your existing telemetry may not work properly.
The initialization file is the same for both CommonJS and ESM applications. The SDK automatically registers ESM loader hooks when running in an ESM environment (Node.js >= 18.19.0 or >= 20.6.0).
// tuskDriftInit.ts or tuskDriftInit.js
import { TuskDrift } from "@use-tusk/drift-node-sdk";
// Initialize SDK immediately
TuskDrift.initialize({
apiKey: process.env.TUSK_API_KEY,
env: process.env.NODE_ENV,
});
export { TuskDrift };Note: ESM applications still require the
--importflag when starting Node.js. See Step 2 for details.
| Option | Type | Default | Description |
|---|---|---|---|
apiKey |
string |
Required if using Tusk Cloud | Your Tusk Drift API key. |
env |
string |
process.env.NODE_ENV |
The environment name. |
logLevel |
'silent' | 'error' | 'warn' | 'info' | 'debug' |
'info' |
The logging level. |
samplingRate |
number |
1.0 |
Override sampling rate (0.0 - 1.0) for recording. Takes precedence over TUSK_SAMPLING_RATE env var and config file. |
registerEsmLoaderHooks |
boolean |
true |
Automatically register ESM loader hooks for module interception. Set to false to disable if import-in-the-middle causes issues with certain packages. See Troubleshooting ESM. |
See also: Environment Variables guide for detailed information about environment variables.
You need to know whether your application uses CommonJS or ESM (ECMAScript Modules) because the entry point setup differs.
If your application uses require():
- Your application is CommonJS
If your application uses import statements:
- This could be either CommonJS or ESM, depending on your build configuration
- Check your compiled output (if you compile to a directory like
dist/):- If the compiled code contains
require()statements → CommonJS application - If the compiled code contains
importstatements → ESM application
- If the compiled code contains
- If you don't compile your code (running source files directly):
- It is an ESM application
In your main server file (e.g., server.ts, index.ts, app.ts), require the initialized SDK at the very top, before any other requires:
// e.g. server.ts
import { TuskDrift } from "./tuskDriftInit"; // MUST be the first import
// ... other imports ...
// Your application setup...IMPORTANT: Ensure NO require calls are made before requiring the SDK initialization file. This guarantees proper instrumentation of all dependencies.
For ESM applications, you cannot control import order within your application code because all imports are hoisted. Instead, use the --import flag:
Update your package.json scripts:
{
"scripts": {
"dev": "node --import ./dist/tuskDriftInit.js dist/server.js",
"dev:record": "TUSK_DRIFT_MODE=RECORD node --import ./dist/tuskDriftInit.js dist/server.js"
}
}Why --import is required for ESM: In ESM, all import statements are hoisted and evaluated before any code runs, making it impossible to control import order within a file. The --import flag ensures the SDK initialization happens in a separate phase before your application code loads, guaranteeing proper module interception.
The sampling rate determines what percentage of requests are recorded during replay tests. Tusk Drift supports three ways to configure the sampling rate, with the following precedence (highest to lowest):
- Init Parameter
- Environment Variable (
TUSK_SAMPLING_RATE) - Configuration File (
.tusk/config.yaml)
If not specified, the default sampling rate is 1.0 (100%).
Set the sampling rate directly in your initialization code:
TuskDrift.initialize({
apiKey: process.env.TUSK_API_KEY,
env: process.env.NODE_ENV,
samplingRate: 0.1, // 10% of requests
});Set the TUSK_SAMPLING_RATE environment variable:
# Development - record everything
TUSK_SAMPLING_RATE=1.0 npm run dev
# Production - sample 10% of requests
TUSK_SAMPLING_RATE=0.1 npm startUpdate the configuration file .tusk/config.yaml to include a recording section. Example recording configuration:
# ... existing configuration ...
recording:
sampling_rate: 0.1
export_spans: true
enable_env_var_recording: true| Option | Type | Default | Description |
|---|---|---|---|
sampling_rate |
number |
1.0 |
The sampling rate (0.0 - 1.0). 1.0 means 100% of requests are recorded, 0.0 means 0% of requests are recorded. |
export_spans |
boolean |
false |
Whether to export spans to Tusk backend or local files (.tusk/traces). If false, spans are only exported to local files. |
enable_env_var_recording |
boolean |
false |
Whether to enable environment variable recording and replaying. Recommended if your application's business logic depends on environment variables, as this ensures the most accurate replay behavior. |
Once your application has completed initialization (database connections, middleware setup, etc.), mark it as ready:
// e.g. server.ts
import { TuskDrift } from "./tuskDriftInit";
// ... other imports ...
const app = express();
// Your application setup...
app.listen(8000, () => {
// Mark app as ready for recording/replay
TuskDrift.markAppAsReady();
console.log("Server started and ready for Tusk Drift");
});The SDK automatically registers ESM loader hooks via import-in-the-middle to intercept ES module imports. Only modules that the SDK instruments have their exports wrapped with getter/setter proxies -- unrelated modules are left untouched.
In rare cases, the wrapping can cause issues with instrumented packages:
- Non-standard export patterns: Some packages use dynamic
export *re-exports or conditional exports that the wrapper's static analysis cannot parse, resulting in runtime syntax errors. - Native or WASM bindings: Packages with native addons loaded via ESM can conflict with the proxy wrapping mechanism.
- Bundler-generated ESM: Code that was bundled (e.g., by esbuild or webpack) into ESM sometimes produces patterns the wrapper does not handle correctly.
- Circular ESM imports: The proxy layer can interact badly with circular ESM import graphs in some edge cases.
If you encounter errors like:
SyntaxError: The requested module '...' does not provide an export named '...'
(node:1234) Error: 'import-in-the-middle' failed to wrap 'file://../../path/to/file.js'
You can disable the automatic ESM hook registration:
TuskDrift.initialize({
apiKey: process.env.TUSK_API_KEY,
env: process.env.NODE_ENV,
registerEsmLoaderHooks: false,
});Note: Disabling ESM loader hooks means the SDK will only be able to instrument packages loaded via CommonJS (
require()). Packages loaded purely through ESMimportstatements will not be intercepted. Node.js built-in modules (likehttp,https,net) are always loaded through the CJS path internally, so they will continue to be instrumented regardless of this setting.