Configuration
Complete configuration reference for SingleTable.
Basic Setup
import { SingleTable } from 'dynamodb-provider';
const table = new SingleTable({
dynamodbProvider: provider,
table: 'YOUR_TABLE_NAME',
partitionKey: 'pk',
rangeKey: 'sk'
});Required Parameters
dynamodbProvider
- Type:
IDynamodbProvider - Required: Yes
An instance of DynamodbProvider.
const provider = new DynamodbProvider({ /* ... */ });
const table = new SingleTable({
dynamodbProvider: provider,
// ...
});table
- Type:
string - Required: Yes
The DynamoDB table name.
const table = new SingleTable({
dynamodbProvider: provider,
table: 'AppData',
// ...
});partitionKey
- Type:
string - Required: Yes
The partition key column name in DynamoDB.
const table = new SingleTable({
dynamodbProvider: provider,
table: 'AppData',
partitionKey: 'pk', // Column name in DynamoDB
// ...
});rangeKey
- Type:
string - Required: Yes
The range key column name in DynamoDB.
const table = new SingleTable({
dynamodbProvider: provider,
table: 'AppData',
partitionKey: 'pk',
rangeKey: 'sk', // Column name in DynamoDB
});Optional Parameters
keySeparator
- Type:
string - Default:
#
Separator used to join key paths.
const table = new SingleTable({
dynamodbProvider: provider,
table: 'AppData',
partitionKey: 'pk',
rangeKey: 'sk',
keySeparator: '#' // ['USER', '123'] becomes 'USER#123'
});Examples:
// With default '#'
partitionKey: ['USER', id] // → 'USER#id'
rangeKey: ['ORDER', orderId] // → 'ORDER#orderId'
// With custom separator
keySeparator: '::'
partitionKey: ['USER', id] // → 'USER::id'typeIndex
- Type:
object - Optional
Index configuration for entity type identification. Required for listType, listAllFromType, findTableItem, and filterTableItens methods.
Treat this as your "table name" column. While we do recommend creating an Index to easily manage all your entities, you can get by configuring it just to have the column set up on every item. It is strongly recommended to mark items by their type as single table's best practices.
typeIndex: {
partitionKey: string; // Column name for type identifier
rangeKey: string; // Column name for sort key
name: string; // Index name in DynamoDB
rangeKeyGenerator?: (item, type) => string | undefined;
}Example:
const table = new SingleTable({
dynamodbProvider: provider,
table: 'AppData',
partitionKey: 'pk',
rangeKey: 'sk',
typeIndex: {
name: 'TypeIndex',
partitionKey: '_type',
rangeKey: '_timestamp',
rangeKeyGenerator: (item, type) => new Date().toISOString()
}
});Default Range Key Generator:
If not specified, defaults to new Date().toISOString():
// Default behavior
rangeKeyGenerator: () => new Date().toISOString()Skip Range Key:
Return undefined to skip range key creation:
rangeKeyGenerator: () => undefinedCustom Range Key:
rangeKeyGenerator: (item, type) => {
// Use item property as range key
return item.createdAt || new Date().toISOString();
}Index Existence:
The index does NOT need to exist in DynamoDB if only using the type property for filtering. The index MUST exist for query-based methods like listType and listAllFromType.
expiresAt
- Type:
string - Optional
TTL column name if configured in DynamoDB.
const table = new SingleTable({
dynamodbProvider: provider,
table: 'AppData',
partitionKey: 'pk',
rangeKey: 'sk',
expiresAt: 'ttl' // DynamoDB TTL column
});
// Use with create
await table.create({
key: { partitionKey: ['SESSION', '123'], rangeKey: '#DATA' },
item: { sessionId: '123', data: '...' },
expiresAt: Math.floor(Date.now() / 1000) + 3600 // Expires in 1 hour
});indexes
- Type:
Record<string, { partitionKey: string; rangeKey: string; numeric?: boolean; }> - Optional
Secondary index configuration.
const table = new SingleTable({
dynamodbProvider: provider,
table: 'AppData',
partitionKey: 'pk',
rangeKey: 'sk',
indexes: {
// Index name as defined in DynamoDB
EmailIndex: {
partitionKey: 'gsih1', // GSI partition key column
rangeKey: 'gsir1' // GSI range key column
},
StatusIndex: {
partitionKey: 'gsih2',
rangeKey: 'gsir2'
},
LeaderboardIndex: {
partitionKey: 'gsih3',
rangeKey: 'gsir3',
numeric: true // Enable atomic operations on this index's range key
}
}
});
// Use with create
await table.create({
key: { partitionKey: 'USER#123', rangeKey: '#DATA' },
item: { userId: '123', name: 'John', email: 'john@example.com' },
indexes: {
// type safe object key
EmailIndex: {
partitionKey: 'john@example.com',
rangeKey: new Date().toISOString()
}
}
});Numeric Indexes:
Set numeric: true on an index to enable atomic operations on its range key. This allows safe atomic updates (add, subtract, sum) on numeric index range keys without worrying about blockInternalPropUpdate restrictions or knowing internal column names.
const table = new SingleTable({
dynamodbProvider: provider,
table: 'AppData',
partitionKey: 'pk',
rangeKey: 'sk',
indexes: {
LeaderboardIndex: {
partitionKey: 'lbPK',
rangeKey: 'score', // Numeric range key
numeric: true, // Enable atomic operations
},
RankIndex: {
partitionKey: 'rankPK',
rangeKey: 'rank',
numeric: true,
},
},
});
await table.update({
partitionKey: ['PLAYER', 'player-123'],
rangeKey: '#DATA',
values: { name: 'Updated Name' },
atomicIndexes: [
{
index: 'LeaderboardIndex',
type: 'add',
value: 500,
},
{
index: 'RankIndex',
type: 'subtract',
value: 1,
if: {
operation: 'bigger_than',
value: 0,
},
},
],
});autoRemoveTableProperties
- Type:
boolean - Default:
true
Removes internal properties from returned items:
- Main table partition and range keys
- Type index partition and range keys
- All secondary index partition and range keys
- TTL attribute
const table = new SingleTable({
dynamodbProvider: provider,
table: 'AppData',
partitionKey: 'pk',
rangeKey: 'sk',
autoRemoveTableProperties: true // Default
});
// In DynamoDB:
{
pk: 'USER#123',
sk: '#DATA',
userId: '123',
name: 'John'
}
// Returned:
{
userId: '123',
name: 'John'
}Disable cleanup:
autoRemoveTableProperties: false
// Returns all properties including pk, sk, etc.⚠️ Important
Best practices: Items should contain all relevant properties independently without relying on key extraction. For example, if PK is USER#id, include an id property in the item. As a rule of thumb, single table columns should be low level and not relied as app-level values.
keepTypeProperty
- Type:
boolean - Default:
false
Retains the typeIndex partition key column in returned items. Only applies when autoRemoveTableProperties is true. This
const table = new SingleTable({
dynamodbProvider: provider,
table: 'AppData',
partitionKey: 'pk',
rangeKey: 'sk',
typeIndex: {
partitionKey: '_type',
rangeKey: '_timestamp',
name: 'TypeIndex'
},
keepTypeProperty: true
});
// Returned item includes _type:
{
_type: 'USER',
userId: '123',
name: 'John'
}propertyCleanup
- Type:
(item: AnyObject) => AnyObject - Optional
Custom cleanup function for returned items. Overrides autoRemoveTableProperties and keepTypeProperty when provided.
const table = new SingleTable({
dynamodbProvider: provider,
table: 'AppData',
partitionKey: 'pk',
rangeKey: 'sk',
propertyCleanup: (item) => {
// Custom cleanup logic
const { pk, sk, _internal, ...cleaned } = item;
return cleaned
}
});blockInternalPropUpdate
- Type:
boolean - Default:
true
Blocks updates to internal properties (keys, index keys, type key, TTL). Default behavior throws error if attempted.
const table = new SingleTable({
dynamodbProvider: provider,
table: 'AppData',
partitionKey: 'pk',
rangeKey: 'sk',
blockInternalPropUpdate: true // Default
});
// ❌ Throws error
await table.update({
partitionKey: 'USER#123',
rangeKey: '#DATA',
values: {
_type: 'NEW_VALUE' // Error: Cannot update internal property
}
});badUpdateValidation
- Type:
(propertiesInUpdate: Set<string>) => boolean | string - Optional
Custom validation for update operations. Receives all properties referenced in values, remove, or atomicOperations.
const table = new SingleTable({
dynamodbProvider: provider,
table: 'AppData',
partitionKey: 'pk',
rangeKey: 'sk',
badUpdateValidation: (properties) => {
// Block updates to specific properties
if (properties.has('immutableField')) {
return 'Cannot update immutableField';
}
// Check multiple properties
const protectedFields = ['createdBy', 'createdAt', 'id'];
for (const field of protectedFields) {
if (properties.has(field)) {
return `Cannot update protected field: ${field}`;
}
}
return false; // Validation passed
}
});Return values:
true- Update is invalid (throws generic error)false- Update is validstring- Custom error message to throw
Note: The partition key check always runs as it violates DynamoDB rules.
autoGenerators
- Type:
Record<string, () => any> - Optional
Define custom value generators that can be referenced in entity autoGen configurations.
Extends or overrides the built-in auto-generation types (UUID, KSUID, timestamp, count).
const table = new SingleTable({
dynamodbProvider: provider,
table: 'AppData',
partitionKey: 'pk',
rangeKey: 'sk',
autoGenerators: {
// Add custom generators
tenantId: () => getTenantFromContext(),
organizationId: () => getOrgFromContext(),
requestId: () => generateRequestId(),
// Override built-in generators
UUID: () => customUUIDImplementation(),
timestamp: () => new Date().toISOString(),
}
});Built-in Generators:
UUID- Generates v4 UUIDKSUID- Generates K-Sortable Unique IDtimestamp- Generates ISO timestampcount- Assigns 0
Using with Schema:
const User = table.schema.createEntity<UserType>().as({
type: 'USER',
getPartitionKey: ({ id }) => ['USER', id],
getRangeKey: () => '#DATA',
autoGen: {
onCreate: {
id: 'UUID', // Uses built-in or custom UUID
tenantId: 'tenantId', // Uses custom tenantId generator
createdAt: 'timestamp', // Uses built-in or custom timestamp
},
onUpdate: {
updatedAt: 'timestamp',
requestId: 'requestId'
}
}
});Complete Example
const table = new SingleTable({
// Required
dynamodbProvider: provider,
table: 'AppData',
partitionKey: 'pk',
rangeKey: 'sk',
// Optional
keySeparator: '#',
typeIndex: {
name: 'TypeIndex',
partitionKey: '_type',
rangeKey: '_timestamp',
rangeKeyGenerator: () => new Date().toISOString()
},
expiresAt: 'ttl',
indexes: {
EmailIndex: {
partitionKey: 'gsipk1',
rangeKey: 'gsisk1'
},
StatusIndex: {
partitionKey: 'gsipk2',
rangeKey: 'gsisk2'
}
},
autoRemoveTableProperties: true,
keepTypeProperty: false,
blockInternalPropUpdate: true,
badUpdateValidation: (properties) => {
const immutableFields = ['id', 'createdAt', 'createdBy'];
for (const field of immutableFields) {
if (properties.has(field)) {
return `Cannot update immutable field: ${field}`;
}
}
return false;
},
autoGenerators: {
tenantId: () => getCurrentTenant(),
organizationId: () => getCurrentOrganization(),
}
});See Also
- Provider Setup - DynamoDB Provider configuration
- Methods - SingleTable operations
- Schema - Entity modeling with autoGenerators