Remix Integration
This guide explains how to integrate FileZen with Remix applications. We recommend using our dedicated SDK packages for the best experience.
📁 Code Example: View the complete working example at github.com/FileZen/filezen/tree/main/sdks/filezen-remix
Installation
Install the required FileZen packages for a Remix project:
Setup
1. Environment Configuration
Set your FileZen API key as an environment variable. This can be done in your local .env file during development or as a system environment variable in production.
FILEZEN_API_KEY=your_api_key_hereThe FileZen SDK automatically detects the FILEZEN_API_KEY environment variable for server-side operations, so no additional configuration is needed in your resource routes.
2. Resource Route
The resource route is crucial for security, as it keeps your API key on the server and prevents it from being exposed in the client-side code.
Create a resource route to handle file uploads and other operations. The createZenRemixRouter function from @filezen/remix simplifies this process by creating the necessary action and loader functions.
import { ZenApi } from '@filezen/js';
import { createZenRemixRouter } from '@filezen/remix';
// The ZenApi class will automatically pick up the FILEZEN_API_KEY from environment variables.
const zenApi = new ZenApi();
export const { action, loader } = createZenRemixRouter(zenApi);By default, the client expects this route at /api/upload. You should create this file at app/routes/api.upload.tsx. If you wish to use a different path, you can create the route file elsewhere and specify the new path in the ZenClientProvider.
Request Validation Middleware (Optional)
You can add request validation middleware to verify requests before generating signed URLs for file uploads. This is useful for implementing authentication, authorization, or other custom validation logic.
import { ZenApi, ZenError } from '@filezen/js';
import { createZenRemixRouter } from '@filezen/remix';
import type { ActionFunctionArgs, LoaderFunctionArgs } from '@remix-run/node';
const zenApi = new ZenApi();
const requestMiddleware = async (request: Request) => {
/**
* Here you can verify request, e.g - check user authentication:
* const user = await getUserFromRequest(request);
* if (!user) {
* throw new ZenError(401, 'Unauthorized');
* }
* return { userId: user.id }
*/
};
export const { action, loader } = createZenRemixRouter(zenApi, {
onRequest: requestMiddleware,
});The middleware function can:
- Return additional metadata that will be available in the request context
- Throw a ZenError to reject the request with a specific status code and message
- Return void or undefined if no additional processing is needed
3. Provider Setup
Wrap your application’s root layout with the ZenClientProvider. This makes the ZenClient instance available to all components in your application via the useZenClient hook.
When using @filezen/remix, you do not need to pass any props to the provider if you use the default API route path (/api/upload).
import { ZenClientProvider } from '@filezen/react';
import type { LinksFunction, MetaFunction } from '@remix-run/node';
export const meta: MetaFunction = () => {
return [{ title: 'FileZen Remix Example' }];
};
export default function App() {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<ZenClientProvider>
{/* Your app content */}
</ZenClientProvider>
</body>
</html>
);
}If you have customized the API route path, you must provide the signUrl prop to the ZenClientProvider.
import { ZenClientProvider } from '@filezen/react';
export default function App() {
return (
<html lang="en">
<body>
<ZenClientProvider signUrl="/api/your-custom-path">
{/* Your app content */}
</ZenClientProvider>
</body>
</html>
);
}Using the Hook
Once the provider is set up, you can use the useZenClient hook in any client component to access the upload functionality:
import { useZenClient } from '@filezen/react';
// Get the client instance
const zenClient = useZenClient();
// Upload a file
const result = await zenClient.upload(file);
if (result.file) {
console.log('Upload successful:', result.file.url);
}File Upload Component Example
With the provider and resource route set up, you can now create a client component to handle file uploads. The useZenClient hook provides a zenClient instance that communicates with your resource route.
import { ZenFile } from '@filezen/js';
import { useZenClient } from '@filezen/react';
import React from 'react';
import { useDropzone } from 'react-dropzone';
export const FileUpload = () => {
const zenClient = useZenClient();
const [isUploading, setIsUploading] = React.useState(false);
const [uploadResult, setUploadResult] = React.useState<ZenFile | null>(null);
const handleUpload = async (file: File) => {
setIsUploading(true);
const result = await zenClient.upload(file);
setIsUploading(false);
if (result.file) {
setUploadResult(result.file);
} else {
console.error(result.error);
}
};
const onDrop = React.useCallback((acceptedFiles: File[]) => {
if (acceptedFiles.length > 0) {
handleUpload(acceptedFiles[0]);
}
}, []);
const { getRootProps, getInputProps } = useDropzone({ onDrop });
return (
<div>
<div {...getRootProps()} style={{ border: '2px dashed #ccc', padding: '20px', cursor: 'pointer' }}>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
</div>
{isUploading && <p>Uploading...</p>}
{uploadResult && (
<div>
<p>File uploaded successfully!</p>
<a href={uploadResult.url} target="_blank" rel="noopener noreferrer">
<img src={uploadResult.url} alt="Upload preview" style={{ maxWidth: '200px' }} />
</a>
</div>
)}
</div>
);
};Using Components in Remix Pages
Use your components in Remix pages:
import type { MetaFunction } from '@remix-run/node';
import { FileUpload } from '~/components/FileUpload';
export const meta: MetaFunction = () => {
return [{ title: 'FileZen Remix Example' }];
};
export default function Index() {
return (
<div>
<h1>FileZen Upload Example</h1>
<p>
This example demonstrates how to use FileZen for file uploads with Remix.
The upload is handled with resource routes and server-side processing.
</p>
<FileUpload />
</div>
);
}The
zenClient.upload()method requests a signed URL from your resource route (/api/upload), then uploads the file directly to FileZen from the client side. This reduces traffic usage on your server since files don’t pass through your backend.
API Reference
createZenRemixRouter(api, options?)
Creates Remix action and loader functions for file uploads.
Parameters
api: ZenApi- FileZen API instanceoptions?: CreateZenRouterOptions- Optional configuration
Returns
action: ActionFunction- Remix action for POST requests (uploads)loader: LoaderFunction- Remix loader for DELETE requests (deletions)
Dependencies
This package requires:
@filezen/js- Core FileZen SDK@filezen/react- React hooks and providers@remix-run/node- Remix server utilitiesreact- React library