Skip to content
Dashboard
Create 6 min read

NextStorage Object Storage

Buckets, API keys, uploads, object URLs, and usage for NextStorage on NexHost.

NextStorage Object Storage#

NextStorage is Nexthomelabs' fourth product alongside NexHost, ProperInbox, and Nextsend: S3-style object storage for applications. Create buckets in the dashboard, generate a NextStorage API key, upload files through the NextStorage API, and serve them from your nexthomelabs.net object URLs. Every workspace starts with a 10 GB free quota.

What is NextStorage#

NextStorage gives every workspace:

  • Buckets — logical containers similar to R2 or S3 buckets.
  • Objects — files addressed by a path-like object key and a unique object UID.
  • API keysnhs_live_… credentials for programmatic uploads.
  • Object URLshttps://storage.nexthomelabs.net/o/:objectUid delivery addresses.
  • Usage — stored bytes, bandwidth, requests, and object counts.

Creating a Bucket#

  1. Open NextStorage in the dashboard.
  2. Choose Create Bucket.
  3. Enter a bucket name and choose Private (default) or Public.
  4. Open the bucket to upload objects, browse by prefix, or change settings.

Buckets are isolated by workspace. Another workspace cannot list, read, or write your buckets.

Deleting a non-empty bucket requires explicit confirmation.

Endpoint#

The canonical Storage API lives on the dedicated storage host with no backend prefix:

text
https://storage.nexthomelabs.net/v1

Object delivery uses the same host (/o/:objectUid and /b/:bucketUid/:objectKey). The older nexthomelabs.net/api/storage/v1 and nexthomelabs.net/storage/... paths keep working for backward compatibility.

API Authentication#

Every programmatic request uses a workspace API key:

http
Authorization: Bearer nhs_live_xxxxxxxxxxxxxxxxxxxxx

Generating an API Key#

  1. Open NextStorage, then API Access.
  2. Enter a key name and choose permissions.
  3. Choose Generate key.
  4. Copy the full key immediately — it is shown only once.

Available permissions:

  • storage:read
  • storage:write
  • storage:delete
  • buckets:read
  • buckets:write

Revoke a key at any time. Revoked keys stop working immediately.

Uploading Objects#

bash
curl -X POST "https://storage.nexthomelabs.net/v1/buckets/my-assets/objects" \
  -H "Authorization: Bearer nhs_live_CUSTOMER_API_KEY" \
  -F "file=@./photo.jpg" \
  -F "key=images/photo.jpg" \
  -F "visibility=public"

JavaScript:

js
const form = new FormData();
form.append('file', file);
form.append('key', 'products/gown.jpg');
form.append('visibility', 'public');

const response = await fetch('https://storage.nexthomelabs.net/v1/buckets/my-assets/objects', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer nhs_live_CUSTOMER_API_KEY'
  },
  body: form
});

const object = await response.json();
console.log(object.url);

A successful upload returns:

json
{
  "id": "obj_01K5DV7AXY0G6PPDX9M66ACZXQ",
  "bucket": "my-assets",
  "key": "products/gown.jpg",
  "name": "gown.jpg",
  "contentType": "image/jpeg",
  "size": 428193,
  "visibility": "public",
  "status": "available",
  "url": "https://storage.nexthomelabs.net/o/obj_01K5DV7AXY0G6PPDX9M66ACZXQ"
}

Object Keys#

Object keys are path-like names:

  • photo.jpg
  • avatars/user-48/avatar.png
  • products/gowns/gown-001.jpg
  • videos/promos/september.mp4
  • documents/contracts/agreement.pdf

Keys support nested prefixes, unicode filenames, and folder-style listing with ?prefix=images/&search=photo. Path traversal (.., empty segments) is rejected. The object UID is independent from the object key.

Listing Objects#

bash
curl "https://storage.nexthomelabs.net/v1/buckets/my-assets/objects?prefix=images/&limit=100" \
  -H "Authorization: Bearer nhs_live_CUSTOMER_API_KEY"

Retrieving Objects#

Every object has a stable UID URL:

text
https://storage.nexthomelabs.net/o/:objectUid

Bucket-style URLs use the globally unique bucket ID returned by the API:

text
https://storage.nexthomelabs.net/b/:bucketUid/:objectKey

Clients stay on nexthomelabs.net. Delivery streams the object with the correct Content-Type, supports video range requests, and records bandwidth. Public images carry ETag/Last-Modified with browser and edge caching, so repeat <img> loads resolve to a fast 304 instead of a full download.

Public Buckets#

A public bucket is a bucket-wide grant: every current and future object can be opened through its NextStorage URL without authentication. Use this for a dedicated website-assets bucket where all files are intended for public delivery.

If the bucket is private, individual objects can still be made public from the Objects tab or through the API. This is the safer choice when only selected images, videos, or documents should be public.

bash
curl -X PATCH "https://storage.nexthomelabs.net/v1/buckets/my-assets/objects/images/photo.jpg" \
  -H "Authorization: Bearer nhs_live_CUSTOMER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"visibility":"public"}'

Public URLs are delivery URLs, not API-only URLs. They return the real file with its stored Content-Type, so a public image can be used directly in frontend markup:

html
<img
  src="https://storage.nexthomelabs.net/o/obj_01K5DV7AXY0G6PPDX9M66ACZXQ"
  alt="Product photo"
>

Do not place a NextStorage API key in browser code. Public delivery requires no key and includes cross-origin headers for websites and apps on other domains.

Private Buckets#

Private buckets are the default. A private object requires one of:

  1. A logged-in workspace session — open the same-origin URL (/api/storage/o/:uid) in a

browser signed into the owning workspace. The dashboard preview does exactly this, so a private image in a private bucket renders for members with bucket access and for nobody else.

  1. A signed URL — mint GET /storage/objects/:uid/signed-url while logged in, then embed

the returned ?expires&sig URL in an <img> on any site. It is bound to that team, object, and expiry (default 15 minutes, max 24 hours) and needs no session or API key to render.

  1. A NextStorage API key with storage:read scoped to the team/bucket (Authorization: Bearer nhs_live_…).
bash
curl "https://nexthomelabs.com/api/storage/objects/obj_01K5DV7AXY0G6PPDX9M66ACZXQ/signed-url" \
  -H "Cookie: nexhost_session=YOUR_SESSION"
# {"url":"https://storage.nexthomelabs.net/o/obj_…?expires=…&sig=…","expiresAt":"…"}
html
<img src="https://storage.nexthomelabs.net/o/obj_01K5DV7AXY0G6PPDX9M66ACZXQ?expires=1757865600&sig=abc123" alt="Private product photo">

Making a public bucket private locks every object in that bucket. Selected objects can then be published again individually. Unauthenticated requests to private objects receive a branded private file page during browser navigation and a machine-readable FORBIDDEN response for API requests.

Videos and large files#

Every video container is accepted (mp4, mov, webm, mkv, avi, and the rest) and single files may use the full 10 GB quota. Uploads are quota-gated, not format-gated: a 5 GB video succeeds while free quota remains and counts toward the 10 GB that unlocks paid storage. Keep the browser tab open until progress reaches 100% — large uploads stream to disk on the server and forward with an extended upstream timeout.

Two upload paths, different ceilings:

  • Dashboard browser upload (same-origin /api/storage/...) crosses the CDN and tops out

around 95 MB per file. Fine for images and short clips.

  • Storage-host upload (https://storage.nexthomelabs.net/v1/... with a NextStorage API key)

bypasses that CDN cap, so multi-GB videos succeed:

bash
curl -X POST "https://storage.nexthomelabs.net/v1/buckets/my-assets/objects" \
  -H "Authorization: Bearer nhs_live_CUSTOMER_API_KEY" \
  -F "file=@./big-video.mkv" \
  -F "key=videos/big-video.mkv" -F "visibility=private"

Chunked/resumable browser uploads for multi-GB files are planned next; until then the API path above is the supported route for anything over ~95 MB.

Deleting Objects#

bash
curl -X DELETE "https://storage.nexthomelabs.net/v1/buckets/my-assets/objects/images%2Fphoto.jpg" \
  -H "Authorization: Bearer nhs_live_CUSTOMER_API_KEY"

Encode / in object keys as %2F when calling key-addressed routes. Deletion updates bucket usage immediately.

Usage and Limits#

The dashboard shows buckets, objects, storage used, bandwidth used, and request counts. Uploads check workspace quota before contacting storage, and oversized uploads are rejected with STORAGE_QUOTA_EXCEEDED or UPLOAD_FAILED. The free tier is 10 GB per workspace with up to 25 buckets; single objects may be up to 10 GB.

Errors#

NextStorage returns its own error codes:

CodeMeaning
INVALID_API_KEYThe supplied NextStorage API key is invalid.
BUCKET_NOT_FOUNDThe requested NextStorage bucket was not found.
OBJECT_NOT_FOUNDThe requested NextStorage object was not found.
STORAGE_QUOTA_EXCEEDEDYour NextStorage storage quota has been exceeded.
UPLOAD_FAILEDNextStorage could not complete the upload.
STORAGE_UNAVAILABLENextStorage is temporarily unable to access this object.