Tulip Logo IconTulip
Storage

Server

Use the Storage service on the server for uploads, reads, signed URLs, and asset lifecycle operations.

Tulip's server-side storage API lives on the Storage service. Once you have added storage to your app context, backend code can upload files, read existing assets, generate signed URLs, and manage deletion and cleanup.

When to use the server API

Use the server API when:

  • your app generates a PDF, CSV, image, or archive
  • your backend already has the file bytes
  • you need to read or process stored files on the server
  • you need signed URLs in server code
  • you need delete, restore, or purge operations

If the upload starts with a user selecting a file in the browser, use /docs/storage/client instead.

Access the service

Most server code uses the storage service through your app context.

const asset = await context.storage.getAssetById(assetId);

In practice, context.storage is your shared Storage instance from /docs/storage/setup.

Upload directly from the server

Use storage.upload() when the file bytes already exist on the server or are generated there.

const asset = await context.storage.upload({
  name: "report.pdf",
  body: fileBuffer,
  contentType: "application/pdf",
  size: fileBuffer.byteLength,
  visibility: "private",
  metadata: { source: "report-job" },
});

This flow:

  1. validates the input
  2. creates a pending asset row
  3. uploads the bytes through the adapter
  4. marks the asset as ready
  5. marks the asset as error if the upload fails

Supported body types

The server upload API accepts:

  • string
  • Uint8Array
  • Buffer
  • Node.js Readable

That makes it a good fit for generated files, stream output, and content loaded from other systems.

Read an existing object

Use getObject() when you need the file bytes on the server.

const object = await context.storage.getObject(assetId);

console.log(object.contentType);
console.log(object.size);

The returned body is a Node.js readable stream. This is useful when you need to merge PDFs, inspect files, or transform stored content.

In demo-spark, this pattern is used while generating technical sheet PDFs from existing source files.

Generate a signed read URL

Use getObjectURL() when server code needs a temporary provider URL.

const url = await context.storage.getObjectURL(assetId, {
  expiresIn: 3600,
  disposition: "inline",
});

This is useful when:

  • a server-rendered document needs a temporary image URL
  • backend code needs to hand off a short-lived provider URL
  • you want signed access outside the normal /api/storage/files/:id route flow

In demo-spark, this pattern is used to resolve a temporary cover image URL for generated technical sheet PDFs.

Delete, restore, and purge assets

The storage service supports three different lifecycle operations.

Soft delete

Use deleteAsset() or deleteAssets() to mark assets as deleted by setting deletedAt.

await context.storage.deleteAssets(ids);

This keeps the database rows and provider objects in place.

Restore

Use restoreAsset() or restoreAssets() to undo a soft delete.

await context.storage.restoreAsset(assetId);

Purge

Use purgeAsset() or purgeAssets() to permanently remove both the provider objects and the database records.

await context.storage.purgeAsset(assetId);

Use purge carefully because it is the irreversible cleanup path.

About browser upload internals

The Storage service also exposes presignUpload() and confirmUpload(), but those are usually wrapped by createStorageProcedures() and consumed through createUploadClient().

For most browser-driven upload flows, use /docs/storage/client instead of calling those methods directly in your UI.

Quick guidance

  • Use upload() when the file bytes are already on the server.
  • Use getObject() when backend code needs the actual file body.
  • Use getObjectURL() when backend code needs a temporary signed URL.
  • Use delete, restore, and purge to manage asset lifecycle.

If you want to render or download assets in the UI, continue with /docs/storage/serving-files.

On this page