Site icon Filestack Blog

How to Integrate Filestack with SolidStart Using the JavaScript SDK

solidstart featured image

You picked Solid for fine-grained reactivity and a small runtime. File uploads should not pull you back into managing storage buckets and a CDN. Filestack’s JavaScript SDK handles that layer, so a single component and one API route give you a working, secured upload that stays in app code. Create a free API key and build it as you read.

On the client, a signal pair tracks the upload state. On the server, a file in src/routes/api signs the short-lived credentials that keep your app secret off the browser. That is the whole boundary, and once it is in place your components talk to a plain SDK client.

Every snippet runs against the real filestack-js SDK. Copy them in order and you will have a working upload, signed credentials, and a resized image by the end.

Key takeaways

Before you start

You need:

Pull your API key and app secret from the Filestack developer portal. The API key is fine in client code. The app secret stays on the server and signs every policy.

Step 1: Install and set environment variables

Install the SDK:

npm install filestack-js

Add your keys to .env:

VITE_FILESTACK_API_KEY=Axxxxxxxxxxxxxxxxxxxxx

FILESTACK_APP_SECRET=your-app-secret-here

SolidStart runs on Vite, so anything prefixed with VITE_ reaches the browser through import.meta.env. The app secret has no prefix, so it stays server-only and you read it with process.env inside the API route.

Step 2: Get a working upload with the public key

Filestack apps start with security off, so an API key is enough for your first upload. Edit src/routes/index.tsx:

 

import { createSignal, onMount, Show } from 'solid-js';

import type { Client } from 'filestack-js';




export default function Home() {

  let client: Client;

  const [result, setResult] = createSignal<any>(null);

  const [uploading, setUploading] = createSignal(false);




  onMount(async () => {

    const filestack = await import('filestack-js');

    client = filestack.init(import.meta.env.VITE_FILESTACK_API_KEY);

  });





  async function handleFile(e: Event) {

    const file = (e.currentTarget as HTMLInputElement).files?.[0];

    if (!file) return;

    setUploading(true);

    setResult(await client.upload(file));

    setUploading(false);

  }




  return (

    <main>

      <input type="file" onChange={handleFile} />

      <Show when={uploading()}>

        <p>Uploading...</p>

      </Show>

      <Show when={result()}>

        <p>Uploaded {result().filename}</p>

        <img src={result().url} alt={result().filename} width="320" />

      </Show>

    </main>

  );

}

Run npm run dev, pick a file, and you have a working upload. The resolved object carries result().handle, result().url, result().filename, result().mimetype, and result().size. Save the handle in your database, since it is the durable identifier you reuse for signed reads, transformations, and deletes. The URL is convenience metadata.

Step 3: Sign a policy on the server

Once you turn on security in the developer portal, every upload needs a policy and a signature. Both come from a short-lived security policy signed with your app secret. Create src/routes/api/filestack-creds.ts:

import { json } from '@solidjs/router';

import type { APIEvent } from '@solidjs/start/server';

import { createHmac } from 'node:crypto';




function signPolicy(policy: object, secret: string) {

  const encoded = Buffer.from(JSON.stringify(policy))

    .toString('base64')

    .replace(/\+/g, '-')

    .replace(/\//g, '_');

  const signature = createHmac('sha256', secret).update(encoded).digest('hex');

  return { policy: encoded, signature };

}




export function GET(event: APIEvent) {

  const policy = {

    expiry: Math.floor(Date.now() / 1000) + 300, // valid for 5 minutes

    call: ['pick', 'store', 'read', 'convert']

  };

  return json(signPolicy(policy, process.env.FILESTACK_APP_SECRET as string));

}

This route returns a five-minute credential scoped to the calls you allow. Keep it behind your own auth so only signed-in users can request one, and follow the security best practices for scoping and expiry. The app secret stays in process.env on the server, and the browser only ever sees the encoded policy and its signature.

Step 4: Upload with the signed credentials

Update the handler to fetch credentials first, then initialize the client with that security object:

async function handleFile(e: Event) {

  const file = (e.currentTarget as HTMLInputElement).files?.[0];

  if (!file) return;

  setUploading(true);

  const filestack = await import('filestack-js');

  const security = await fetch('/api/filestack-creds').then((r) => r.json());

  const secured = filestack.init(import.meta.env.VITE_FILESTACK_API_KEY, { security });

  setResult(await secured.upload(file));

  setUploading(false);

}

 

The user experience is identical. The client now carries a signed, expiring policy, so Filestack accepts the upload on a secured app.

Step 5: Resize on delivery

Filestack transformations happen at delivery time. Build a CDN URL from the returned handle:

<Show when={result()}>

  <img

    src={`https://cdn.filestackcontent.com/resize=width:600/${result().handle}`}

    alt={result().filename}

  />

</Show>

The resize runs on the Filestack Processing Engine and the result is cached on the CDN, so your SolidStart server never touches the bytes. With security on, append the read credentials as query parameters:

const src =

  `https://cdn.filestackcontent.com/resize=width:600/${result().handle}` +

  `?policy=${security.policy}&signature=${security.signature}`;

Putting it all together

One component, one API route, and the real SDK. A signal pair drives the UI, the route signs short-lived policies with node:crypto, the app secret stays in process.env, and a resize is a URL built from the handle. The upload layer never leaks into the rest of your Solid code.

Start free. Sign up for an API key, drop in the component and the policy route above, and you have secured uploads and transformations running the same afternoon. When you are ready to scale, Filestack pricing tracks uploads, transformations, and bandwidth, so the bill follows real usage.

 

Exit mobile version