Skip to main content

Development

This page explains how to manage assets using the Juno SDK, including uploading, listing, counting, and deleting files within your application. It also covers configuration options for optimizing storage and access control.

important

The functions described on this page are intended for use in the client-side of your app.

If you're looking to extend backend capabilities using serverless logic, refer to the Functions documentation.


Upload file

When you upload a file, it becomes an asset stored in the Storage of your Satellite. Assets are accessible over the web and can be listed, deleted, or protected using tokens.

To upload a file, use the following code:

import { uploadFile } from "@junobuild/core";

const result = await uploadFile({
data,
collection: "images"
});

Parameters

The data parameter is the file you want to upload. This is a Blob, typically selected using an HTML <input type="file" /> element.

The uploadFile function provides various options, including:

  • filename: By default, Juno uses the file's filename. You can overwrite this and provide a custom filename. Example: myimage.jpg.
  • fullPath: The unique path where the asset will be stored and accessed. 👉 See What is a fullPath? for details and examples.
  • headers: The headers can affect how the browser handles the asset. If no headers are provided Juno will infer the Content-Type from the file type.
  • encoding: The type of encoding for the file. For example, identity (raw) or gzip.
note
  • URL encoding is currently not supported on the Internet Computer. Therefore, it's important to keep in mind that your filename should not be encoded. That is why the library decodes the filename automatically.

Returns

The function returns the uploaded asset key as an object with the following fields:

  • fullPath: The unique path to the asset. Example: /images/myimage.jpg.
  • name: The name of the asset (typically the filename). Example: myimage.jpg.
  • downloadUrl: The URL to access the asset on the web or to download it. This URL can be used in a browser or embedded directly in HTML elements like <img> or <a>.

What is a fullPath?

The fullPath is the unique path of an asset within your Satellite's storage. It determines the asset’s public-facing URL and is used throughout the SDK to identify, retrieve, list, or delete the asset.

It always starts with a slash, and follows the structure:

/collection/filename

For example, uploading a file to the "images" collection with the filename "logo.png" results in:

/images/logo.png

Key points

  • If the asset is not part of the frontend, the fullPath always includes the collection name.
  • By default, the fullPath is automatically derived from the uploaded file's name (e.g. /images/photo.jpg).
  • You can override the path using a custom filename. These are both valid:
  • /collection/hello.jpg
  • /collection/my/sub/path/hello.jpg
  • The fullPath is effectively the asset key used in Juno Storage.
  • ⚠️ Uploading a file to an existing fullPath will overwrite the existing file.

Upload blob

The uploadBlob function works like uploadFile but does not infer the filename from the data. You must explicitly provide the filename.

import { uploadBlob } from "@junobuild/core";

const result = await uploadBlob({
data: new Blob([myBuffer]),
filename: "generated.jpg",
collection: "images"
});

This is useful when uploading raw binary data that wasn't selected via a file input.


Protected assets

While all assets can be found on the internet, it is possible to make their URL difficult to guess so that they remain undiscoverable (as long as they are not shared) and considered "private".

Juno achieves this by using an optional token query parameter.

import { uploadFile } from "@junobuild/core";
import { nanoid } from "nanoid";

const result = await uploadFile({
data,
collection: "images",
token: nanoid()
});

Imagine a file "mydata.jpg" uploaded with a token. Attempting to access it through the URL "https://yoursatellite/mydata.jpg" will not work. The asset can only be retrieved if a token is provided: "https://yoursatellite/mydata.jpg?token=a-super-long-secret-id".


List assets

The listAssets function is used to retrieve assets from a specified collection.

import { listAssets } from "@junobuild/core";

const myList = await listAssets({
collection: "my_collection_key"
});

Parameters

The function requires a collection and accepts various optional parameters, including a matcher (a regex applied to the assets fullPaths and descriptions), pagination options, and sorting order.

note

listAssets uses the same interface as listDocs. That is why the parameter matcher expect a value key to filter the assets according their fullPath.

  1. collection (required)

    • Description: The key of the collection from which assets are to be listed.
    • Type: string
  2. filter (optional)

    • Description: An optional object that can be used to provide various parameters to filter assets.

    a. matcher (optional)

    • Description: An object used to filter assets based on their keys (fullPaths) or descriptions using regular expressions.

    • Type: ListMatcher

      interface ListMatcher {
      key?: string;
      description?: string;
      createdAt?: ListTimestampMatcher;
      updatedAt?: ListTimestampMatcher;
      }
      • key: A regex to match against asset keys.
      • description: A regex to match against asset descriptions.
      • createdAt: A ListTimestampMatcher to filter assets based on their creation timestamp.
      • updatedAt: A ListTimestampMatcher to filter assets based on their last update timestamp.
    • Type: ListTimestampMatcher can be used to specify criteria for timestamp matching.

      type ListTimestampMatcher =
      | {
      matcher: "equal";
      timestamp: bigint;
      }
      | {
      matcher: "greaterThan";
      timestamp: bigint;
      }
      | {
      matcher: "lessThan";
      timestamp: bigint;
      }
      | {
      matcher: "between";
      timestamps: {
      start: bigint;
      end: bigint;
      };
      };
      • matcher: Specifies the type of timestamp comparison. Can be one of the following:

        • equal: Matches assets where the timestamp is exactly equal to the specified value.
        • greaterThan: Matches assets where the timestamp is greater than the specified value.
        • lessThan: Matches assets where the timestamp is less than the specified value.
        • between: Matches assets where the timestamp falls within a specified range.
      • timestamp: Used with equal, greaterThan, and lessThan matchers to specify the exact timestamp for comparison.

      • timestamps: Used with the between matcher to specify a range of timestamps. The range is inclusive of both the start and end values.

    b. paginate (optional)

    • Description: An object to control pagination of the results

    • Type: ListPaginate

      interface ListPaginate {
      startAfter?: string;
      limit?: number;
      }
      • startAfter: A string key to start listing assets after this key.
      • limit: The maximum number of assets to return.

    c. order (optional)

    • Description: Control the sorting order of the results.

    • Type: ListOrder

      interface ListOrder {
      desc: boolean;
      field: ListOrderField;
      }

      type ListOrderField = "keys" | "updated_at" | "created_at";

    d. owner (optional)

    • Description: The owner of the assets.

    • Type: ListOwner

      type ListOwner = string | Principal;
Example

Usage of the parameters:

import { listDocs } from "@junobuild/core";

const myList = await listDocs({
collection: "my_collection_key",
filter: {
matcher: {
key: ".*.png$", // match assets with .png extension
description: "holiday", // match description containing 'holiday'
createdAt: {
matcher: "greaterThan",
timestamp: 1627776000n
},
updatedAt: {
matcher: "between",
timestamps: {
start: 1627770000n,
end: 1627900000n
}
}
},
paginate: {
startAfter: "doc_10",
limit: 5
},
order: {
desc: true,
field: "updated_at"
},
owner: "some_owner_id_or_principal"
}
});

The function returns the assets and various information, in the form of an object whose interface is given below.

{
items: []; // The data - array of assets without their content
items_length: bigint; // The number of assets - basically items.length
items_page?: bigint; // If the query is paginated, at what page (starting from 0) do the items find the place
matches_length: bigint; // The total number of matching results
matches_pages?: bigint; // If the query is paginated, the total number (starting from 0) of pages
}

Download URL

The downloadUrl function is used to generate a public URL for accessing a specific asset stored on a Satellite.

note

You get similar information directly from the result of an upload. This function can be used to generate the URL on the fly.

This URL can be used to:

  • Open the file directly in a browser
  • Embed the asset in HTML elements such as <img src="..."> or <a href="...">
  • Trigger a download when used in an <a href="..." download> link
import { downloadUrl } from "@junobuild/core";

const url = downloadUrl({
assetKey: {
fullPath: "/images/logo.png",
token: "a-secret-token" // optional
}
});

// Example usage
<img src={url} alt="Logo" />

Parameters

  • assetKey (required)

  • fullPath: The full path to the asset (e.g., /images/file.jpg).

  • token (optional): A secret token used to access protected assets.

  • satellite (optional) Required only in Node.js environments to specify which Satellite to use.

Returns

  • A string representing the full URL to access the asset.
note

If a token is provided when uploading the asset, it must also be included in the URL to access it. This makes the asset effectively private until shared with the token.


Count assets

The countAssets function is used to count the number of assets in a specified collection without retrieving the actual assets.

import { countAssets } from "@junobuild/core";

const assetCount = await countAssets({
collection: "my_collection_key"
});

Usage

This function accepts similar parameters as the listAssets function, including collection, matcher, and owner, and returns the count of matching documents.

For detailed information on how to use these parameters, refer to the List assets section.

The return value is the same as the items_length property from the listAssets function, providing the count of assets that match the criteria.


Delete

There are multiple ways to delete assets from your Storage.

Delete asset

To delete an asset, you only need to provide its fullPath. Unlike the datastore, there is no timestamp validation performed when deleting an asset.

import { deleteAsset } from "@junobuild/core";

await deleteAsset({
collection: "images",
storageFile: myAsset
});

Delete multiple assets

To delete multiple assets in an atomic manner, you can use the function deleteManyAssets:

import { deleteManyAssets } from "@junobuild/core";

const myAsset1 = {
collection: "hello",
fullPath: "/hello/world.jpg"
};

const myAsset2 = {
collection: "data",
fullPath: "/data/something.json"
};

await deleteManyAssets({ assets: [myAsset1, myAsset2] });

Delete filtered assets

The deleteFilteredAssets function allows you to delete multiple assets from a collection based on specific filter criteria. This function simplifies bulk deletions by leveraging the same parameters as the listAssets function for filtering.

import { deleteFilteredAssets } from "@junobuild/core";

await deleteFilteredAssets({
collection: "my_collection_key",
filter: {
// Uses the same filter options as listAssets
}
});

Options

This section covers additional options that can be used with most of the functions listed above.

Certified Reads

All read functions support a certified option that can be enabled to guarantee cryptographic verification of the returned data.

By default, uncertified reads are used for better performance and UX. Those are faster but do not provide cryptographic guarantees.

When options.certified is enabled, the function performs an update call under the hood. This ensures the response is verified by the Internet Computer but may increase latency.

When to Use Certified Reads

Certified reads matter when trust in displayed information is more important than speed, or when your app exposes publicly verifiable data — such as user balances, or voting results.

For those use cases, a common pattern is deduplicating the call: making an uncertified call for UX purposes — fetching and displaying data quickly — and an update call in parallel, which might take longer but ensures verification. If the latter fails, revert the information and warn users about the issue.

Example

import { listAssets } from "@junobuild/core";

await listAssets({
collection: "my_collection_key",
options: { certified: true }
});

Node.js Usage

In Node.js or outside the browser, you must explicitly pass a satellite parameter specifying the satellite configuration, so the function knows which satellite to target and how to connect to it.

This is required because initSatellite() is only available in browser environments.

important

You never need to set this parameter in a browser context.

Example

import { getAsset } from "@junobuild/core";

await getAsset({
collection: "my_collection_key",
fullPath: "/images/logo.png",
satellite: {
identity: myIdentity,
satelliteId: "aaaaa-bbbbb-ccccc-ddddd-cai",
container: true
}
});