Developer
News and Updates
Get Support
Sign in
Get Support
Sign in
DOCUMENTATION
Cloud
Data Center
Resources
Sign in
Sign in
DOCUMENTATION
Cloud
Data Center
Resources
Sign in
Key-Value Store
Custom Entity Store
SQL
Object Store (Preview)
Last updated Jun 22, 2026

Storing, downloading, and deleting large objects

Forge Object Store is now in Preview, and therefore fully supported. However, it remains under active development and may be subject to shorter deprecation windows. Preview features are suitable for early adopters in production environments.

We release preview features so partners and developers can study, test, and integrate them prior to General Availability (GA). For more details, see Forge EAP, Preview, and GA.

The Forge Object Store API lets you upload, download, and manage large items (like data objects and media files) directly from your app. This API also lets you create pre-signed URLs for download and upload requests.

To start using the Forge Object Store, add the required package (@forge/object-store) to your project first:

1
2
npm install @forge/object-store

Then, import the package to your app, as follows:

1
2
import fos from '@forge/object-store'

To integrate the Forge Object Store with your app's frontend, use the objectStore bridge methods.

Limitations

The Forge Object Store has the following limitations:

Rate limits per installation

If the following rate limits are exceeded, Forge will return a TOO_MANY_REQUESTS error.

ParameterLimit
Object Store requests per minute5000
Pre-signed URL requests per second1000

Operation limits

When building interfaces for object download/uploads, you must use the available frontend components.

ParameterLimit
Maximum object size 1 GB
Maximum request payload size 1 kB
Pre-signed URL validity1 hour

The maximum object size applies to objects uploaded through any frontend component used in conjunction with the Forge Object Store (for example, the useObjectStore UI Kit hook).

Meanwhile, the maximum request payload size only applies to the actual Forge Object Store request. This request should only contain the object's name and other relevant metadata (not the object itself).

Versioning

If you add Forge Object Store to an existing app, admins of that app's current installations must review and consent before updating.

As such, adding Forge Object Store to an existing app will require a major version upgrade. This will be triggered through the objectStore module (which is required to enable the feature on an app).

Get metadata

Retrieve the metadata for objects stored in the Forge-hosted object store using the get method.

To integrate with the frontend, use the objectStore bridge API's get method.

Method signature

1
2
fos.get(key: string, options?: { cdn?: boolean }): Promise<ObjectReference | undefined>;

interface ObjectReference {
  key: string;
  checksum: string;
  size: number;
  createdAt?: string;
  updatedAt?: string;
  currentVersion?: string;
} 

This method accepts the following properties:

PropertyTypeRequiredDescription
keystringYesThe unique identifier for the object metadata to retrieve.
optionsobjectNoAdditional options for the request.
options.cdnbooleanNoWhether to retrieve metadata from the CDN bucket (defaults to false). The CDN bucket is the storage bucket that backs CDN URLs — only objects uploaded to the CDN bucket can be served over the CDN. Objects stored in the default bucket cannot be shared via CDN URLs.

Returns: The ObjectReference if found, or undefined if the object does not exist.

Example

1
2
export const getObjectRef = async (key: string): Promise<ObjectReference | undefined> => {
  try {
    const objectRef = await fos.get(key);
    if (objectRef === undefined) {
      console.info('Object was not found', { key })
    }
    return objectRef
  } catch (error) {
    console.error('Error getting object reference', JSON.stringify(error))
  }
};

Delete

Remove objects from the Forge-hosted object store using the delete method.

To integrate with the frontend, use the objectStore bridge API's deleteObjects method.

Method signature

1
2
fos.delete(key: string, options?: { cdn?: boolean }): Promise<void>;

This method accepts the following properties:

PropertyTypeRequiredDescription
keystringYesThe unique identifier for the object to delete.
optionsobjectNoAdditional options for the request.
options.cdnbooleanNoWhether to delete the object from the CDN bucket (defaults to false).

Example

1
2
export const deleteObject = async (key: string): Promise<void> => {
  try {
    await fos.delete(key)
  } catch (error) {
    console.error('Error deleting object', JSON.stringify(error))
  }
}

Create download URL

To create a URL with temporary permissions to download a specific object, use the createDownloadUrl method. The created URL will expire after 1 hour.

To integrate with the frontend, use the objectStore bridge API's download method.

If you need a pre-signed URL accessible to browsers or clients outside of Atlassian Cloud, use createPublicDownloadUrl instead.

Don’t store pre-signed URLs in a global context. Doing this could potentially let customer data persist across app invocations between different installations. See Developer responsibilities for related information.

Method signature

1
2
fos.createDownloadUrl(key: string, options?: { cdn?: boolean }): Promise<PresignedUrlResponse | undefined>

interface PresignedUrlResponse {
  url: string;
}

This method accepts the following properties:

PropertyTypeRequiredDescription
keystringYesThe unique identifier for the object. The createDownloadUrl method uses this as a unique identifier for your URL.
optionsobjectNoAdditional options for the request.
options.cdnbooleanNoWhether to generate a download URL from the CDN bucket (defaults to false).

Returns: A PresignedUrlResponse. The object's content-type will be what was specified via the pre-signed upload URL; otherwise, the content-type will be application/octet-stream.

Use a GET operation to download an object via the returned PresignedUrlResponse. This GET operation accepts the Range header to download parts of the object. For example, the following header will request the first 500 bytes of the object:

1
2
Range: bytes=0-499

Example

1
2
export const createDownloadUrl = async (key: string): Promise<PresignedUrlResponse | undefined> => {
  try {
    return await fos.createDownloadUrl(key);
  } catch (error) {
    console.error('Error creating pre-signed download URL', JSON.stringify(error))
  }
};

export const downloadUsingUrl = async (objectId: string): Promise<any> => {
  const { url } = await createDownloadUrl(objectId);
  if (url) {
    const response = await fetch(url);
    if (response.ok) {
      return response;
    } else {
      console.error('Failed to download object: ', objectId);
    }
  }
};

Create public download URL

To create a pre-signed download URL accessible to browsers and clients outside of Atlassian Cloud, use the createPublicDownloadUrl method. The created URL will expire after 1 hour.

If you need a pre-signed download URL for use inside Atlassian Cloud (such as within Lambda resolvers), use createDownloadUrl instead.

Don't store pre-signed URLs in a global context. Doing this could potentially let customer data persist across app invocations between different installations. See Developer responsibilities for related information.

Method signature

1
2
fos.createPublicDownloadUrl(key: string, options?: { cdn?: boolean }): Promise<PresignedUrlResponse | undefined>

This method accepts the following properties:

PropertyTypeRequiredDescription
keystringYesThe unique identifier for the object.
optionsobjectNoAdditional options for the request.
options.cdnbooleanNoWhether to generate a download URL from the CDN bucket (defaults to false).

Returns: A PresignedUrlResponse. The object's content-type will be what was specified via the pre-signed upload URL; otherwise, the content-type will be application/octet-stream.

Use a GET operation to download an object via the returned PresignedUrlResponse. This GET operation accepts the Range header to download parts of the object. For example, the following header will request the first 500 bytes of the object:

1
2
Range: bytes=0-499

Example

1
2
export const createPublicDownloadUrl = async (key: string): Promise<PresignedUrlResponse | undefined> => {
  try {
    return await fos.createPublicDownloadUrl(key);
  } catch (error) {
    console.error('Error creating public pre-signed download URL', JSON.stringify(error));
  }
};

export const downloadUsingPublicUrl = async (objectId: string): Promise<any> => {
  const { url } = await createPublicDownloadUrl(objectId);
  if (url) {
    const response = await fetch(url);
    if (response.ok) {
      return response;
    } else {
      console.error('Failed to download object: ', objectId);
    }
  }
};

Create upload URL

To create a URL with temporary permissions to upload a single object, use the createUploadUrl method. Pre-signed upload URLs can only be used for objects under 1GB. The created URL will expire after 1 hour.

To integrate with the frontend, use the objectStore bridge API's upload method.

If you need a pre-signed URL accessible to browsers or clients outside of Atlassian Cloud, use createPublicUploadUrl instead.

Don’t store pre-signed URLs in a global context. Doing this could potentially let customer data persist across app invocations between different installations. See Developer responsibilities for related information.

Method signature

1
2
fos.createUploadUrl(body: UploadUrlBody): Promise<PresignedUrlResponse>

interface UploadUrlBody {
  key: string;
  length: number;
  checksum: string;
  checksumType: 'SHA1' | 'SHA256' | 'CRC32' | 'CRC32C';
  ttlSeconds?: number;
  overwrite?: boolean;
  cdn?: boolean;
}

interface PresignedUrlResponse {
  url: string;
}

When generating a pre-signed upload URL through createUploadUrl, your request must include an UploadUrlBody containing the properties of the file you’re uploading. These properties are:

PropertyTypeRequiredDescription
keystringYesThe unique identifier for the object.
lengthnumberYesThe byte size of the object.
checksumstringYesHash digest of the file content, encoded as base64. Used to verify data integrity.
checksumTypestringYesAlgorithm used to generate the checksum.
ttlSecondsnumberNoAllows you to set a custom TTL for an object.
overwritebooleanNoIndicates whether to replace an existing object with the same key. Defaults to true.
cdnbooleanNoWhether to upload the object to the CDN bucket. Objects in the CDN bucket may be cached (defaults to false).

Returns: A PresignedUrlResponse.

Use a PUT operation to upload an object via the returned PresignedUrlResponse. This PUT operation does not require any additional headers.

However, we strongly advise that you send the content-type header, as this value will be retained on the object and returned when downloaded. By default, objects will use application/octet-stream as their content-type header.

Example

1
2
export const createUploadUrl = async (key: string, object: any, objectLength: number, ttlSeconds?: number): Promise<PresignedUrlResponse | undefined> => {
  try {
    const bufferedObject = Buffer.from(object)
    // Create SHA256 checksum from buffer
    const checksum = crypto.createHash('sha256').update(bufferedObject).digest('base64');
    const body: UploadUrlBody = {
      key: key,
      length: objectLength,
      checksum,
      checksumType: 'SHA256',
      ttlSeconds,
      overwrite: true,
    };
    const resp = await fos.createUploadUrl(body);
    return resp;
  } catch (error) {
    console.error('Error creating pre-signed upload URL', JSON.stringify(error))
  }
};

export const uploadUsingUrl = async (uploadObjectProperties: any): Promise<void> => {
  const { objectId, object, objectLength, ttlSeconds } = uploadObjectProperties
  const { url } = await createUploadUrl(objectId, object, objectLength, ttlSeconds);
  if (url) {
    const response = await fetch(url, {
      method: 'PUT',
      headers: {
        'content-type': 'application/octet-stream', // or the actual content type of your object
      },
      body: object,
    });
    if (!response.ok) {
      console.error('Failed to upload object: ', objectId);
    }
  }
};

Create public upload URL

To create a URL with temporary permissions to upload a single object for browsers and clients outside of Atlassian Cloud, use the createPublicUploadUrl method. Pre-signed upload URLs can only be used for objects under 1GB. The created URL will expire after 1 hour.

If you need a pre-signed URL for frontend integration via the objectStore bridge API, use createUploadUrl instead.

Don't store pre-signed URLs in a global context. Doing this could potentially let customer data persist across app invocations between different installations. See Developer responsibilities for related information.

Method signature

1
2
fos.createPublicUploadUrl(body: UploadUrlBody): Promise<PresignedUrlResponse>

interface UploadUrlBody {
  key: string;
  length: number;
  checksum: string;
  checksumType: 'SHA1' | 'SHA256' | 'CRC32' | 'CRC32C';
  ttlSeconds?: number;
  overwrite?: boolean;
  cdn?: boolean;
}

interface PresignedUrlResponse {
  url: string;
}

When generating a pre-signed upload URL through createPublicUploadUrl, your request must include an UploadUrlBody containing the properties of the file you're uploading. These properties are:

PropertyTypeRequiredDescription
keystringYesThe unique identifier for the object.
lengthnumberYesThe byte size of the object.
checksumstringYesHash digest of the file content, encoded as base64. Used to verify data integrity.
checksumTypestringYesAlgorithm used to generate the checksum.
ttlSecondsnumberNoAllows you to set a custom TTL for an object.
overwritebooleanNoIndicates whether to replace an existing object with the same key. Defaults to true.
cdnbooleanNoWhether to upload the object to the CDN bucket. Objects in the CDN bucket may be cached (defaults to false).

Returns: A PresignedUrlResponse.

Use a PUT operation to upload an object via the returned PresignedUrlResponse. This PUT operation does not require any additional headers.

However, we strongly advise that you send the content-type header, as this value will be retained on the object and returned when downloaded. By default, objects will use application/octet-stream as their content-type header.

Example

1
2
export const createPublicUploadUrl = async (key: string, object: any, objectLength: number, ttlSeconds?: number): Promise<PresignedUrlResponse | undefined> => {
  try {
    const bufferedObject = Buffer.from(object)
    // Create SHA256 checksum from buffer
    const checksum = crypto.createHash('sha256').update(bufferedObject).digest('base64');
    const body: UploadUrlBody = {
      key: key,
      length: objectLength,
      checksum,
      checksumType: 'SHA256',
      ttlSeconds,
      overwrite: true,
    };
    const resp = await fos.createPublicUploadUrl(body);
    return resp;
  } catch (error) {
    console.error('Error creating public pre-signed upload URL', JSON.stringify(error))
  }
};

export const uploadUsingPublicUrl = async (uploadObjectProperties: any): Promise<void> => {
  const { objectId, object, objectLength, ttlSeconds } = uploadObjectProperties
  const { url } = await createPublicUploadUrl(objectId, object, objectLength, ttlSeconds);
  if (url) {
    const response = await fetch(url, {
      method: 'PUT',
      headers: {
        'content-type': 'application/octet-stream', // or the actual content type of your object
      },
      body: object,
    });
    if (!response.ok) {
      console.error('Failed to upload object: ', objectId);
    }
  }
};

Create CDN URL

To generate a CDN URL for accessing an object, use the createCDNUrl method. Unlike pre-signed URLs, CDN URLs serve cached content for faster delivery.

Method signature

1
2
fos.createCDNUrl(key: string, options?: CDNOptions): Promise<PresignedUrlResponse | undefined>

type CDNOptions = {
  ttlSeconds?: number;
};

When generating a URL through createCDNUrl, supply the following properties in your request:

PropertyTypeRequiredDescription
keystringYesThe unique identifier for the object.
optionsCDNOptionsNoOptional configuration for the CDN URL.
options.ttlSecondsnumberNoTTL for the CDN URL in seconds. Must be greater than 0 and at most 2,505,600 seconds (29 days).

Example

1
2
export const getCDNUrl = async (key: string, options?: CDNOptions): Promise<PresignedUrlResponse | undefined> => {
  try {
    return await fos.createCDNUrl(key, options);
  } catch (error) {
    console.error('Error creating CDN URL', JSON.stringify(error));
  }
};

Rate this page: