Product and environment defaults
Many SDK operations need a product tag and environment slug (dev, prd, etc.). In TypeScript, set both only on the Ductape constructor. They are then inherited when you omit product and env from connect() and from query payloads (after a connection is established).
Do not rely on ductape.configure(), DUCTAPE_PRODUCT / DUCTAPE_ENV environment variables, or product.init(product, env) for runtime defaults. product.init(tag) only pre-loads the product builder.
Constructor
- TypeScript
- Java
- Go
- .NET
import Ductape from '@ductape/sdk';
const ductape = new Ductape({
accessKey: process.env.DUCTAPE_ACCESS_KEY!,
});
// Omit product/env — taken from the constructor
await ductape.databases.connect({ database: 'main-db' });
await ductape.databases.find({
table: 'users',
where: { status: 'active' },
limit: 10,
});
await ductape.graph.connect({ graph: 'social' });
await ductape.vector.connect({ vector: 'embeddings' });
// Same defaults apply to actions, sessions, storage, caches, notifications, quotas, fallbacks, and healthchecks
await ductape.api.run({ app: 'stripe', action: 'create-charge', input: { amount: 1000, currency: 'usd' } });
await ductape.sessions.create({ tag: 'user-session', data: { userId: '1' } });
await ductape.storage.upload({ storage: 'main', file: buffer, fileName: 'doc.pdf' });
await ductape.caches.set({ cache: 'user-cache', key: 'user:1', value: '{}' });
await ductape.notifications.email.send({
notification: 'emails:welcome',
input: { recipients: ['a@b.com'], subject: {}, template: {} },
});
import app.ductape.sdk.Ductape;
import app.ductape.sdk.core.EnvType;
import app.ductape.sdk.core.RequestContext;
RequestContext auth = new RequestContext(null, null, null, null, System.getenv("DUCTAPE_ACCESS_KEY")!);
Ductape ductape = new Ductape(EnvType.PRODUCTION, auth);
// Omit product/env — taken from the constructor
ductape.databases().connect(Map<String, Object>.of(
"database", "main-db" ));
ductape.databases().query(Map<String, Object>.of(
"table", "users",
where: Map.of( "status", "active" ),
"limit", 10,
));
ductape.graphs().connect(Map<String, Object>.of(
"graph", "social" ));
ductape.vectors().connect(Map<String, Object>.of(
"vector", "embeddings" ));
// Same defaults apply to actions, sessions, storage, caches, notifications, quotas, fallbacks, and healthchecks
ductape.api().run(Map<String, Object>.of(
"app", "stripe", "action", "create-charge", input: Map.of( "amount", 1000, "currency", "usd" ) ));
ductape.sessions.create(Map.of( "tag", "user-session", data: Map.of( "userId", "1" ) ));
ductape.storage.upload(Map.of( "storage", "main", file: buffer, "fileName", "doc.pdf" ));
ductape.caches.set(Map.of( "cache", "user-cache", "key", ""user", 1", "value", "Map.of()" ));
ductape.notifications.email.send(Map.of(
"notification", "emails:welcome",
input: Map.of( recipients: ['a@b.com'], subject: Map.of(), template: Map.of() ),
));
import (
"context"
"github.com/ductape/ductape/sdk/go/core"
"github.com/ductape/ductape/sdk/go/ductape"
)
auth := core.NewRequestContext("", "", "", "", os.Getenv("DUCTAPE_ACCESS_KEY")!)
client, err := client.New(core.EnvProduction, auth)
if err != nil {
return err
}
// Omit product/env — taken from the constructor
client.Databases.Connect(ctx, map[string]any{
"database": "main-db" });
client.Databases.Query(ctx, map[string]any{
"table": "users",
where: { "status": "active" },
"limit": 10,
});
client.GraphAPI.Connect(ctx, map[string]any{
"graph": "social" });
client.VectorAPI.Connect(ctx, map[string]any{
"vector": "embeddings" });
// Same defaults apply to actions, sessions, storage, caches, notifications, quotas, fallbacks, and healthchecks
client.Api.Run(ctx, map[string]any{
"app": "stripe", "action": "create-charge", input: { "amount": 1000, "currency": "usd" } });
client.sessions.create({ "tag": "user-session", data: { "userId": "1" } });
client.storage.upload({ "storage": "main", file: buffer, "fileName": "doc.pdf" });
client.caches.set({ "cache": "user-cache", "key": ""user": 1", "value": "{}" });
client.notifications.email.send({
"notification": "emails:welcome",
input: { recipients: ['a@b.com'], subject: {}, template: {} },
});
using Ductape.Sdk;
using Ductape.Sdk.Core;
var auth = new RequestContext(null, null, null, null, Environment.GetEnvironmentVariable("DUCTAPE_ACCESS_KEY")!, null);
var ductape = new Ductape(EnvType.Production, auth);
// Omit product/env — taken from the constructor
await ductape.Database.Connect(new Dictionary<string, object?>
{
["database"] = "main-db" });
await ductape.Database.Query(new Dictionary<string, object?>
{
["table"] = "users",
where: { ["status"] = "active" },
["limit"] = 10,
});
await ductape.Graph.Connect(new Dictionary<string, object?>
{
["graph"] = "social" });
await ductape.Vector.Connect(new Dictionary<string, object?>
{
["vector"] = "embeddings" });
// Same defaults apply to actions, sessions, storage, caches, notifications, quotas, fallbacks, and healthchecks
await await ductape.Api.RunAsync(new Dictionary<string, object?>
{
["app"] = "stripe", ["action"] = "create-charge", input: { ["amount"] = 1000, ["currency"] = "usd" } });
await ductape.sessions.create({ ["tag"] = "user-session", data: { ["userId"] = "1" } });
await ductape.storage.upload({ ["storage"] = "main", file: buffer, ["fileName"] = "doc.pdf" });
await ductape.caches.set({ ["cache"] = "user-cache", ["key"] = "["user"] = 1", ["value"] = "{}" });
await ductape.notifications.email.send({
["notification"] = "emails:welcome",
input: { recipients: ['a@b.com'], subject: {}, template: {} },
});
You may still pass product or env on a specific call to override the constructor for that call only.
Resolution order
When a method needs product and env:
- Values on the current call (if provided)
- Active connection context (after
databases.connect,graph.connect, etc.) productandenvfrom the constructor
If none apply, the SDK throws an error asking you to set both on new Ductape({ accessKey, product, env }).
Shared module pattern
Create one instance and reuse it (credentials can still come from env vars — only the constructor registers defaults):
- TypeScript
- Java
- Go
- .NET
import Ductape from '@ductape/sdk';
export const ductape = new Ductape({
accessKey: process.env.DUCTAPE_ACCESS_KEY!,
product: process.env.DUCTAPE_PRODUCT!,
env: process.env.DUCTAPE_ENV ?? 'dev',
});
import app.ductape.sdk.Ductape;
import app.ductape.sdk.core.EnvType;
import app.ductape.sdk.core.RequestContext;
export Map<String, Object> ductape = new Ductape(Map.of(
accessKey: System.getenv("DUCTAPE_ACCESS_KEY")!,
product: System.getenv("DUCTAPE_PRODUCT")!,
env: System.getenv("DUCTAPE_ENV") ?? 'dev',
));
import (
"context"
"github.com/ductape/ductape/sdk/go/core"
"github.com/ductape/ductape/sdk/go/ductape"
)
export auth := core.NewRequestContext("", "", "", "", os.Getenv("DUCTAPE_ACCESS_KEY")!)
client, err := client.New(core.EnvProduction, auth)
if err != nil {
return err
}
using Ductape.Sdk;
using Ductape.Sdk.Core;
export var ductape = new Ductape({
accessKey: Environment.GetEnvironmentVariable("DUCTAPE_ACCESS_KEY")!,
product: Environment.GetEnvironmentVariable("DUCTAPE_PRODUCT")!,
env: Environment.GetEnvironmentVariable("DUCTAPE_ENV") ?? 'dev',
});
- TypeScript
- Java
- Go
- .NET
import { ductape } from '../lib/ductape';
export async function listActiveUsers() {
await ductape.databases.connect({ database: 'users-db' });
return ductape.databases.find({
table: 'users',
where: { status: 'active' },
});
}
import Map.of( ductape ) from '../lib/ductape';
export async function listActiveUsers() Map.of(
ductape.databases().connect(Map<String, Object>.of(
"database", "users-db" ));
return ductape.databases().query(Map<String, Object>.of(
"table", "users",
where: Map.of( "status", "active" ),
));
)
import "context"
import { ductape } from '../lib/ductape';
export async function listActiveUsers() {
client.Databases.Connect(ctx, map[string]any{
"database": "users-db" });
return client.Databases.Query(ctx, map[string]any{
"table": "users",
where: { "status": "active" },
});
}
import { ductape } from '../lib/ductape';
export async function listActiveUsers() {
await ductape.Database.Connect(new Dictionary<string, object?>
{
["database"] = "users-db" });
return ductape.Database.Query(new Dictionary<string, object?>
{
["table"] = "users",
where: { ["status"] = "active" },
});
}
CLI vs SDK
| CLI | TypeScript SDK | |
|---|---|---|
| Config | .ductape/config.json → product_tag, env_slug | new Ductape({ product, env }) |
| Scope | Linked project + proxy commands | Application singleton |
After ductape link --product my-api --env dev, CLI commands like ductape db query use the linked project automatically. In app code, set the same values on the constructor.
Other SDK languages
Java, Go, and .NET use the same pattern: pass product tag and environment slug on the client constructor, then omit them from connect() and service calls.
Ductape ductape = new Ductape(auth, "my-api", "dev");
ductape.databaseService().connect(Map.of("database", "main-db", "type", "postgres"));
ductape.api().run(Map.of(
"app", "stripe",
"action", "create-charge",
"input", Map.of("amount", 1000, "currency", "usd")));
client := ductape.New(auth, "my-api", "dev")
client.Database.Connect(ctx, map[string]any{"database": "main-db", "type": "postgres"})
client.Actions.Run(ctx, map[string]any{
"app": "stripe", "action": "create-charge",
"input": map[string]any{"amount": 1000, "currency": "usd"},
})
var ductape = new Ductape(auth, "my-api", "dev");
await ductape.Database.ConnectAsync(new Dictionary<string, object?> { ["database"] = "main-db" });
await ductape.Actions.RunAsync(new Dictionary<string, object?> {
["app"] = "stripe", ["action"] = "create-charge",
["input"] = new Dictionary<string, object?> { ["amount"] = 1000, ["currency"] = "usd" },
});
TypeScript is the reference implementation; see each package README for language-specific constructor signatures.