When creating or updating documents, Appwrite automatically sets $createdAt and $updatedAt timestamps. However, there are scenarios where you might need to set these timestamps manually, such as when migrating data from another system or backfilling historical records.
Server SDKs required
To manually set $createdAt and $updatedAt, you must use a server SDK with an API key. These attributes can be passed inside the data parameter on any of the create, update, or upsert routes (single or bulk).
Setting custom timestamps
You can override a document's timestamps by providing ISO 8601 strings (for example, 2025-08-10T12:34:56.000Z) in the data payload. If these attributes are not provided, Appwrite will set them automatically.
Custom timestamps work with all document operations: create, update, upsert, and their bulk variants.
Single document operations
When working with individual documents, you can set custom timestamps during create, update, and upsert operations.
Create with custom timestamps
const sdk = require('node-appwrite');
const client = new sdk.Client()
.setEndpoint('https://<REGION>.cloud.appwrite.io/v1')
.setProject('<PROJECT_ID>')
.setKey('<API_KEY>');
const databases = new sdk.Databases(client);
await databases.createDocument(
'<DATABASE_ID>',
'<COLLECTION_ID>',
sdk.ID.unique(),
{
'$createdAt': new Date('2025-08-10T12:34:56.000Z').toISOString(),
'$updatedAt': new Date('2025-08-10T12:34:56.000Z').toISOString(),
// ...your attributes
}
);
Update with custom timestamps
When updating documents, you can also set a custom $updatedAt timestamp:
await databases.updateDocument(
'<DATABASE_ID>',
'<COLLECTION_ID>',
'<DOCUMENT_ID>',
{
'$updatedAt': new Date('2025-08-10T12:34:56.000Z').toISOString(),
// ...your attributes
}
);
Bulk operations
Custom timestamps also work with bulk operations, allowing you to set different timestamps for each document in the batch:
Bulk create
await databases.createDocuments(
'<DATABASE_ID>',
'<COLLECTION_ID>',
[
{
'$id': sdk.ID.unique(),
'$createdAt': new Date('2024-01-01T00:00:00.000Z').toISOString(),
'$updatedAt': new Date('2024-01-01T00:00:00.000Z').toISOString(),
// ...your attributes
},
{
'$id': sdk.ID.unique(),
'$createdAt': new Date('2024-02-01T00:00:00.000Z').toISOString(),
'$updatedAt': new Date('2024-02-01T00:00:00.000Z').toISOString(),
// ...your attributes
}
]
);
Bulk upsert
await databases.upsertDocuments(
'<DATABASE_ID>',
'<COLLECTION_ID>',
[
{
'$id': '<DOCUMENT_ID_OR_NEW_ID>',
'$createdAt': new Date('2024-01-01T00:00:00.000Z').toISOString(),
'$updatedAt': new Date('2025-01-01T00:00:00.000Z').toISOString(),
// ...your attributes
}
]
);
Common use cases
Custom timestamps are particularly useful in several scenarios:
Data migration
When migrating existing data from another system, you can preserve the original creation and modification times:
await databases.createDocument(
'<DATABASE_ID>',
'blog_posts',
sdk.ID.unique(),
{
'$createdAt': '<ORIGINAL_CREATED_AT_ISO>',
'$updatedAt': '<LAST_MODIFIED_ISO>',
title: '<TITLE>',
content: '<CONTENT>'
}
)
Backdating records
For historical data entry or when creating records that represent past events:
await databases.createDocument(
'<DATABASE_ID>',
'transactions',
sdk.ID.unique(),
{
'$createdAt': '2023-12-31T23:59:59.000Z',
'$updatedAt': '2023-12-31T23:59:59.000Z',
amount: 1000,
type: 'year-end-bonus'
}
)
Synchronization
When synchronizing data between systems while maintaining timestamp consistency:
await databases.upsertDocument(
'<DATABASE_ID>',
'users',
'<DOCUMENT_ID_OR_NEW_ID>',
{
'$updatedAt': '<EXTERNAL_LAST_MODIFIED_ISO>',
profile: '<PROFILE_DATA>'
}
)
Timestamp format and usage
- Values must be valid ISO 8601 date-time strings (UTC recommended). Using
toISOString()(JavaScript) ordatetime.isoformat()(Python) is a good default. - You can set either or both attributes as needed. If omitted, Appwrite sets them automatically.