Learn how to stream data from Linode Object Storage via AWS S3 SDK with simple steps, real code, and a clean setup. A practical guide for fast, reliable file streaming. Our 24/7 Linode Live Support Team is always here to help you.
Working with large files usually slows everything down, especially when you need them delivered instantly to your users. That’s where streaming becomes a lifesaver. Today, I’ll show you how to stream data from Linode Object Storage via AWS S3 SDK using a clean, production-ready approach that developers can drop straight into real projects.
Linode Object Storage is already known for its reliability and S3 compatibility. Meanwhile, the AWS S3 SDK gives developers an easy way to interact with any S3-compatible system. Put both together and you get a fast, efficient way to move files without storing them locally. And yes, this exact method works for images, logs, backups, video files, or anything else you throw at it.

Overview
What You Need Before Starting
Before we dive in, here’s what you need:
- A Linode Object Storage bucket
- An access key + secret key
- AWS SDK installed in your project
- Spin installed if you’re following the full walkthrough
Now let’s move step by step so you never miss a detail.
Steps
Create the Spin App
$ spin new -t http-ts -a linode-streaming-app
$ cd linode-streaming-app
Install AWS S3 Client SDK
$ npm install @aws-sdk/client-s3
Since Linode is fully S3-compatible, this SDK works right away.
Configure Variables in spin.toml
Add this section:
[variables]
region = { required = true }
endpoint = { required = true }
bucket_name = { required = true }
access_key_id = { required = true }
secret_access_key = { required = true, secret = true }
Then attach the variables to the component:
[component.linode-streaming-app.variables]
region = "{{ region }}"
endpoint = "https://{{ endpoint }}"
bucket_name = "{{ bucket_name }}"
access_key_id = "{{ access_key_id }}"
secret_access_key = "{{ secret_access_key }}"
Also allow outbound access:
allowed_outbound_hosts = ['https://{{ bucket_name }}.{{ endpoint }}']
At this point, you’re ready to stream data from Linode Object Storage via AWS S3 SDK with actual code.
Add the Streaming Logic
Replace your src/index.ts with this:
import { AutoRouter, json } from 'itty-router';
import { S3Client, GetObjectCommand, ListObjectsV2Command } from '@aws-sdk/client-s3';
import { Variables } from '@fermyon/spin-sdk';
const dec = new TextDecoder();
const enc = new TextEncoder();
let router = AutoRouter();
List Files
const listFiles = async (config) => {
const s3 = new S3Client({
region: config.region,
endpoint: config.endpoint,
credentials: {
accessKeyId: config.accessKeyId,
secretAccessKey: config.secretAccessKey,
}
});
const { Contents } = await s3.send(new ListObjectsV2Command({ Bucket: config.bucketName }));
return json({ files: Contents?.map((file) => file.Key) || [] });
}
Stream a File
const streamFile = async (name, config) => {
const s3 = new S3Client({
region: config.region,
endpoint: config.endpoint,
credentials: {
accessKeyId: config.accessKeyId,
secretAccessKey: config.secretAccessKey,
}
});
const { Body } = await s3.send(new GetObjectCommand({ Bucket: config.bucketName, Key: name }));
return new Response(Body, { status: 200 });
}
Stream + Transform (Uppercase)
const streamAndTransformFile = async (name, config) => {
const upperCaseTransform = new TransformStream({
transform(chunk, controller) {
const txt = dec.decode(chunk, { stream: true });
controller.enqueue(enc.encode(txt.toUpperCase()));
}
});
const s3 = new S3Client({
region: config.region,
endpoint: config.endpoint,
credentials: {
accessKeyId: config.accessKeyId,
secretAccessKey: config.secretAccessKey,
}
});
const { Body } = await s3.send(new GetObjectCommand({ Bucket: config.bucketName, Key: name }));
return new Response(Body.pipeThrough(upperCaseTransform), { status: 200 });
}
With these handlers, your application can now stream data from Linode without delay or buffering issues.
Stream Faster. Build Faster Today

Build and Run
$ spin build
$ export SPIN_VARIABLE_REGION=se
$ export SPIN_VARIABLE_ENDPOINT=se-sto-1.linodeobjects.com
$ export SPIN_VARIABLE_ACCESS_KEY_ID=XXXXXXXX
$ export SPIN_VARIABLE_SECRET_ACCESS_KEY=XXXXXXXX
$ export SPIN_VARIABLE_BUCKET_NAME=fermyon-blog-bucket
$ spin up
You should see:
Serving http://127.0.0.1:3000
Test Your Streaming Routes
List files:
curl http://127.0.0.1:3000/files
Stream a file:
curl http://127.0.0.1:3000/files/tiny.txt
Transform + stream:
curl http://127.0.0.1:3000/transformed-files/tiny.txt
At this point, you’ve learned how to stream data from Linode cleanly, quickly, and without wasting server space.
Conclusion
If your goal is fast delivery, real-time processing, or handling large files without blocking your server, this method will help you every single time. And since everything here is S3-compatible, you can extend it across any cloud setup you choose.
