Velt Node SDK Best Practices
Implementation guide for @veltdev/node. The SDK has two independent backends that share the same VeltSDK instance but differ in initialization requirements, lazy-load patterns, and response shapes — most bugs stem from blurring that line.
When to Apply
- Initializing
VeltSDK.initialize(...)in a Node service - Calling any method under
sdk.api.*orsdk.selfHosting.* - Generating Velt auth tokens server-side (
getToken) for the frontend - Configuring MongoDB or AWS S3 for self-hosting
- Catching and discriminating SDK errors
- Debugging "result.success is undefined" / "is not a function" / "cannot find module mongodb" symptoms
The two-backend mental model
sdk.api.* is a thin typed wrapper over the Velt REST API. No database needed; service instances are available synchronously after init.
sdk.selfHosting.* is a server-side persistence layer that requires database config; service instances are lazy-loaded via await sdk.selfHosting.getXxx() and cached.
The two return different response envelopes — that's the single highest-impact thing to internalize:
| Backend | Success envelope | Failure |
|---|---|---|
sdk.api.* |
{ result: { status: 'success', message, data, ... } } |
Throws VeltApiError |
sdk.selfHosting.* |
{ success: true, statusCode: 200, data } |
{ success: false, statusCode, error, errorCode } (or throws VeltSDKError subclass) |
Rule Categories
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | Initialization & lifecycle | CRITICAL | init- |
| 2 | sdk.api.* (REST backend) | HIGH | api- |
| 3 | sdk.selfHosting.* (MongoDB + S3) | HIGH | selfhost- |
| 4 | Cross-cutting pitfalls | MEDIUM | pitfalls- |
Quick Reference
1. Initialization & lifecycle
init-dual-mode— Pick the rightVeltSDK.initializeshape (REST-only vs self-hosting) and wireawait sdk.close()on shutdown
2. sdk.api.* (REST backend)
api-envelope-and-services— Use the{ result: { status, data } }envelope; service-by-service method index for all 18 namespaces;organizationIdis required on every methodapi-field-allowlist— Pass{ filterUnknownFields: true }as the second arg to the activities/commentAnnotations/notifications add/update methods to drop unknown keys before the REST write (opt-in, fail-open); reuse via exportedpickKnownFields/filterRequest/FilterSpec
3. sdk.selfHosting.* (MongoDB + S3)
selfhost-lazy-load-and-services— Lazy-load withawait sdk.selfHosting.getXxx(); flat envelope withsuccess+errorCode; per-service method index for all 7 servicesselfhost-attachments-positional—saveAttachment(request, fileBuffer?, fileName?, mimeType?)mixes a request object with positional file args;getAttachment(orgId, attachmentId)is purely positional
4. Cross-cutting pitfalls
pitfalls-token-and-envelopes—getTokenis positional on both backends;sdk.selfHosting.tokenis a sync property (nogetTokenloader); error classes (VeltSDKError+ 4 subclasses) discriminate viainstanceof
How to Use
Read the relevant rule based on what you're writing. The pitfalls-token-and-envelopes rule is worth reading even for unfamiliar tasks — it captures the highest-density "things that silently do the wrong thing".
Compiled Documents
AGENTS.md— Compressed index of all rules (start here)AGENTS.full.md— Full verbose guide