From zero to a processed file with the Transloadit CLI
Process a file from your terminal without copying API secrets. Run auth login, approve the
request in your browser (or sign up there first), and your next command processes a file.
The same CLI can turn a sentence into Assembly Instructions, lint and fix Instructions you wrote by hand, and run them over a whole folder. Below, we walk through each of those against our production API, plus the Node SDK’s answer to uploads that die halfway.
Log in from your browser
The examples below use @transloadit/node 5.1.0. The CLI commands run through npx, so all you need
is Node.js 20.10 or newer:
$ npx -y @transloadit/node auth login
Enter code VKVQ-C5H6 at https://transloadit.com/c/cli-auth?code=VKVQ-C5H6
The CLI opens that page for you. With --no-browser, it only prints the link, which helps over SSH.
Log in, or sign up if you do not have an account yet, check that the code on the page matches the
one in your terminal, and approve. The CLI then prints Logged in to workspace … and you are
ready. Codes expire after 15 minutes.
Approving creates a new Auth Key in your
Workspace, labeled with your machine’s hostname and the
date, so you can find it later under Credentials in the Console. The CLI stores it in
~/.transloadit/credentials, a file only your user can read. That one key can create
Assemblies, read
Templates, and sign
Smart CDN URLs. auth status shows which Workspace you
are logged in to, and auth logout deletes the file and revokes the key. Already have a key?
auth login --stdin imports it from dotenv-style input instead.
Your laptop login is not meant for automation:
- In CI, keep passing
TRANSLOADIT_KEYandTRANSLOADIT_SECRETfrom your secret manager, using a key scoped for that job. Environment variables take precedence over the saved login. - On application servers, use a separate deployment key, so logging out on your laptop never breaks production.
Turn a sentence into a processed file
curl -fsSLo chameleon.jpg https://demos.transloadit.com/inputs/chameleon.jpg
npx -y @transloadit/node run "resize to 400px wide and convert to WebP" -i chameleon.jpg -o chameleon.webp
$ file chameleon.webp
chameleon.webp: RIFF (little-endian) data, WebP image, XMP metadata, EXIF metadata, ICC profile, 400x266
run compiles your sentence into Assembly Instructions, lints the result with the checks described
below, makes up to three attempts if lint finds errors, and then runs the Instructions on your file.
Our 9.3 MB JPEG came back as a 62 KB WebP in about 20 seconds, compile step included.
Compiling is itself an Assembly that uses the 🤖 /ai/chat Robot, so it shows up in your usage like any other Assembly. When you need the same job again, compile once and keep the output:
npx -y @transloadit/node assembly-instructions compile "resize to 400px wide and convert to WebP" > webp-thumbs.json
The generated Instructions can look like this:
{
"steps": {
":original": {
"robot": "/upload/handle"
},
"webp": {
"robot": "/image/resize",
"use": ":original",
"width": 400,
"resize_strategy": "fit",
"zoom": true,
"format": "webp",
"background": "none",
"result": true
}
}
}
That is a single 🤖 /image/resize
Robot Step you
can review, commit, and reuse without calling a model again. A model can return different
Instructions for the same sentence, so read what you keep. For common jobs with fixed flags and no
AI involved, the Intent commands such as image resize
remain the quicker route.
Pass the saved file straight to assemblies create to reuse it:
npx -y @transloadit/node assemblies create --steps webp-thumbs.json -i chameleon.jpg -o saved-thumb.webp
Catch mistakes before production
assemblies lint checks Instructions on your machine with the shared linter used by our Console
editor and MCP server. It needs no credentials, so it runs in CI and pre-commit hooks without
secrets. Here is a file with three common mistakes: a Step without use, a duplicate key, and a
typo in a Step name.
{
"steps": {
":original": { "robot": "/upload/handle" },
"thumb": {
"robot": "/image/resize",
"width": 400,
"height": 300,
"width": 800
},
"optimized": { "robot": "/image/optimize", "use": "thumbs" },
"exported": {
"robot": "/s3/store",
"use": [":original", "thumb", "optimized"],
"credentials": "my-s3-credentials"
}
}
}
$ npx -y @transloadit/node assemblies lint --steps steps.json
[warning] missing-use (3:13) thumb The `use` parameter defines which files a _Robot_ should process. …
[warning] duplicate-key-in-step (7:6) thumb Duplicate key 'width' found
[error] undefined-step (9:54) optimized The _Step_ `optimized` attempts to use the output files from _Step_ `thumbs`, but _Step_ `thumbs` does not exist …
Add --fix, and the linter repairs what it safely can and rewrites the file in place:
$ npx -y @transloadit/node assemblies lint --steps steps.json --fix
[error] undefined-step (13:13) optimized The _Step_ `optimized` attempts to use the output files from _Step_ `thumbs`, but _Step_ `thumbs` does not exist …
The thumb Step now reads:
{
"steps": {
// …
"thumb": {
"robot": "/image/resize",
"width": 800,
"height": 300,
"use": ":original"
},
// …
},
}
--fix kept the last width, the value a JSON parser keeps, pointed the Step at :original, and
reformatted the file. The typo stays, because the linter cannot know which Step you meant. Change
thumbs to thumb, and the file passes, even with warnings treated as failures:
$ npx -y @transloadit/node assemblies lint --steps steps.json --fatal warning
No issues found
Lint exits with a non-zero code on errors, and with --fatal warning on warnings too, so the same
command in a CI job stops broken Instructions before they ship. --steps - reads from stdin,
--json prints machine-readable issues, and --template lints your Steps merged with a saved
Template the way the API merges them. That last option does need credentials.
Process a whole folder
assemblies create runs Instructions over files and directories and downloads the results.
--steps accepts both the Steps-only file below and the { "steps": … } form above. With a few
JPEGs in photos/, this makes 400-pixel-wide thumbnails:
{
":original": { "robot": "/upload/handle" },
"thumb": { "robot": "/image/resize", "use": ":original", "width": 400 }
}
mkdir -p thumbs
npx -y @transloadit/node assemblies create --steps thumbs.json --input photos/ --output thumbs/
Each photo gets its own Assembly, five at a time by default (--concurrency changes that), and each
result lands in thumbs/ under the photo’s file name. Run the command again, and it skips every
photo whose thumbnail is newer than the original, so only new or changed files cost you an
Assembly. --reprocess-stale processes everything again. Add --recursive for subfolders, or
--watch to keep the command running and process files as they change.
Resume uploads after a crash
For large uploads from your own Node.js scripts, the SDK’s resumeAssemblyUploads() continues an
interrupted upload instead of starting over. Install @transloadit/node@5.1.0 in your project and
set TRANSLOADIT_KEY and TRANSLOADIT_SECRET for an application Auth Key configured for SHA-384,
the SDK’s default. These scripts read credentials from environment variables. Download the sample
photo:
curl -fsSLo prinsengracht.jpg https://demos.transloadit.com/inputs/prinsengracht.jpg
Save the Assembly URL as soon as the upload begins:
import { writeFile } from 'node:fs/promises'
import { Transloadit } from '@transloadit/node'
const client = new Transloadit({
authKey: process.env.TRANSLOADIT_KEY,
authSecret: process.env.TRANSLOADIT_SECRET,
})
const upload = client.createAssembly({
params: { steps: { thumb: { robot: '/image/resize', use: ':original', width: 400 } } },
files: { photo: './prinsengracht.jpg' },
chunkSize: 1024 * 1024,
})
// The Assembly ID exists before the first byte is sent, so save it right away.
await writeFile('assembly.txt', `https://api2.transloadit.com/assemblies/${upload.assemblyId}`)
await upload
If that process dies, a second script sends the missing bytes into the same Assembly:
import { readFile } from 'node:fs/promises'
import { Transloadit } from '@transloadit/node'
const client = new Transloadit({
authKey: process.env.TRANSLOADIT_KEY,
authSecret: process.env.TRANSLOADIT_SECRET,
})
const status = await client.resumeAssemblyUploads({
assemblyUrl: await readFile('assembly.txt', 'utf8'),
files: { photo: './prinsengracht.jpg' },
chunkSize: 1024 * 1024,
waitForCompletion: true,
onUploadProgress: ({ uploadedBytes }) => console.log(`${uploadedBytes} bytes uploaded`),
})
console.log(status.ok)
We interrupted the upload of a 14 MB photo with the signal Ctrl+C sends, confirmed the partial upload in the Assembly’s status, and resumed it:
$ node upload.mjs
^C
$ node resume.mjs
1048576 bytes uploaded
1114112 bytes uploaded
…
14160569 bytes uploaded
ASSEMBLY_COMPLETED
The upload continued at 1,048,576 bytes instead of zero. The SDK matches uploads by field name, file name, and size, so pass the same paths as before. Only file-path inputs can resume, not streams or buffers. The API updates partial-upload status asynchronously. If you resume before the partial upload appears in the Assembly’s status, the SDK uploads that file again from the start, still into the same Assembly.
Know the limits
- The browser-login key can run Assemblies and read Templates, but it cannot create or change
Templates.
templatescommands that write need a separate key with that permission. runandcompileuse an AI model, and two runs of the same sentence can produce different Instructions.- On the free Community plan, image results are watermarked, and audio and video results are trimmed. Our FAQ explains why.
Try it
npx -y @transloadit/node auth login
No account yet? Sign up on the page that opens, or create an account first. The CLI overview introduces the tool, and the SDK README documents the commands and upload-resume API. If you would rather have an agent drive Transloadit, see our MCP server and agent skills. Tell us what is missing in the node-sdk issue tracker.
