Skip to content

file://

Filesystem endpoint with a broad surface — ~100 URI parameters covering polling, filtering, read-locking, sorting, atomic writes, idempotent dedup, and on-completion strategies. Consumer polls a directory and dispatches each discovered file into a route. Producer op=write (default) writes the exchange body to a file with configurable existing-file semantics, atomic temp-rename, chmod, fsync, jail, and done-file signalling; producer op=read loads a file's raw bytes into the body — the local-filesystem analog of s3://?operation=getObject, and the native way to turn a path a caller names at runtime into bytes for a downstream consumer (pdf://?op=extractText, xlsx://, docling://, vlm://, …).

For the same surface against a remote server, see ftp:// / ftps:// / sftp://.

URI shape

file://<directory>?<param1>=<value1>&<param2>=<value2>…

<directory> is the path the consumer polls / the producer writes into. Relative paths are resolved to absolute at endpoint creation (except the literal . which is preserved for back-compat). Producer + consumer share an Endpoint, so a to: file://outbox and a from: file://outbox?delete=true operate on the same configured directory.

Parameters

The exhaustive list lives in (*Component).Describe() — pkg/component/file/file.go (function fileParamDescriptors). The sections below summarise the surface; the per-parameter description is the canonical authority.

Common

Param Type Default Description
charset string — Character encoding for transcoding.
doneFileName string — Marker file written by producer / waited for by consumer. Placeholders: ${file.name}, ${file.name.noext}.
fileName string — Consumer: dynamic name filter. Producer: output filename (File-Language).

Consumer

delete, move, moveFailed, preMove, noop, preSort, recursive, sendEmptyMessageWhenIdle, bridgeErrorHandler, directoryMustExist, extendedAttributes, includeHiddenDirs, includeHiddenFiles, inProgressRepository, localWorkDirectory, probeContentType, processStrategy, startingDirectoryMustExist, startingDirectoryMustHaveAccess, stream.

Producer

op (write default / read; operation is an accepted alias), appendChars, checksumFileAlgorithm, checksumWriteFile, fileExist (Override / Append / Fail / Ignore / Move / TryRename), flatten, jailStartingDirectory, moveExisting, tempFileName, tempPrefix, allowNullBody, chmod, chmodDirectory, eagerDeleteTargetFile, forceWrites, keepLastModified.

op=read resolves the file to read per-exchange — from the fileName= URI param, else the HelixFileName / CamelFileName header — joins it against <directory>, and jail-checks it (a header path can't escape the directory unless jailStartingDirectory=false). It sets HelixFileName, HelixFilePath, HelixFileRelativePath, HelixFileLength, and HelixFileLastModified on the message, exactly like a polled file, and errors if no filename is supplied, the file is missing, or the path is a directory.

Filter & sort

antExclude, antFilterCaseSensitive, antInclude, eagerMaxMessagesPerPoll, exclude, excludeExt, filterDirectory, filterFile, idempotent, idempotentEager, idempotentKey, idempotentRepository, include, includeExt, maxDepth, maxMessagesPerPoll, minDepth, move, shuffle, sortBy.

Read-lock

readLock (none / markerFile / changed / rename / fileLock / idempotent / idempotent-changed / idempotent-rename), readLockCheckInterval, readLockDeleteOrphanLockFiles, readLockIdempotentReleaseAsync, readLockIdempotentReleaseDelay, readLockLoggingLevel, readLockMarkerFile, readLockMinAge, readLockMinLength, readLockRemoveOnCommit, readLockRemoveOnRollback, readLockTimeout.

Scheduler

backoffErrorThreshold, backoffIdleThreshold, backoffMultiplier, delay, greedy, initialDelay, poll, repeatCount, runLoggingLevel, scheduler (only none; Quartz/Spring are NOT supported), startScheduler, useFixedDelay.

Misc

autoCreate, autoCreateStepwise, bufferSize, copyAndDeleteOnRenameFail, renameUsingCopy, synchronous.

Body shape

Consumer

For each discovered file:

  • In body — the file contents as []byte, or a lazy *exchange.StreamBody when stream=true.
  • In headers — CamelFileName, CamelFileNameOnly, CamelFileParent, CamelFileAbsolute, CamelFileLength, CamelFileLastModified, plus Content-Type when probeContentType=true.

Producer

  • op=write in body — []byte, string, or io.Reader. allowNullBody=true allows writing a zero-byte file.
  • op=read out body — the file's raw []byte. The input body is irrelevant; the path comes from the fileName= param or the HelixFileName / CamelFileName header.

The producer reads CamelFileName from the exchange (set by upstream steps or inherited from the consumer) to determine the output filename when fileName URI param isn't set.

Examples

Drop-folder consumer with idempotent dedup (auto-enabled when no completion strategy is set):

- id: inbox
  from: file:///var/data/in?include=.*\.csv&delete=true&recursive=true
  steps:
    - to: direct://process-csv

Atomic producer with temp-rename and chmod:

- to: file:///var/data/out?fileName=${date:now:yyyy/MM/dd}/${exchangeId}.json&tempPrefix=.tmp&chmod=640&forceWrites=true

Read a file the caller names at runtime, then process it — the input half of a document skill. The tool-call args arrive as the body ({"path": "report.pdf"}); a set-header moves the path to HelixFileName, op=read loads the bytes, and pdf:// consumes them:

workflows:
  - id: extract-doc
    trigger: { uri: direct://extract }
    steps:
      - set-header: { name: HelixFileName, starlang: payload.path }
      - target: "file:///var/docs?op=read"        # path → raw bytes in body
      - target: "pdf://x?op=extractText"           # bytes → text

Read a JSON config file — a JSON body is auto-parsed, so its fields are directly addressable in the next step:

- target: "file:///etc/app?op=read&fileName=settings.json"
- transform:
    starlang: '{ mode: payload.env, retries: payload.retries }'

Read-lock with changed strategy (don't pick up files still being written):

- id: large-files
  from: file:///incoming?readLock=changed&readLockMinAge=2s&readLockTimeout=30s

Move processed files to a dated archive folder:

- id: archive
  from: file:///in?move=.done/${date:now:yyyy/MM/dd}/${file:name}

Done-file signalling (consumer waits for .ready, producer writes it):

- id: wait-for-done
  from: file:///drop?doneFileName=${file:name.noext}.ready

- to: file:///publish?doneFileName=${file:name.noext}.ready

Behavior notes

  • Idempotent auto-enables. When no completion strategy (move, delete, noop, moveFailed) is configured, the consumer enables idempotent=true so a poll doesn't reprocess the same files forever. Override with idempotent=false.
  • fileLock is local-only. readLock=fileLock uses OS flock/LockFile; it's rejected on the FTP family.
  • Jail. jailStartingDirectory=true (default) refuses writes — and op=read reads — that resolve outside the configured starting directory. Point <directory> at a sandbox root and pass relative (or in-sandbox absolute) paths; set jailStartingDirectory=false to read arbitrary absolute paths.
  • op=read vs the consumer. The polling consumer (from:) reads files it discovers in a fixed directory; op=read (to:) reads a single file the route names at call time. Use the consumer to react to arriving files, op=read to fetch a specific caller-named file mid-route (e.g. backing a document skill's tool).
  • stream=true hands a lazy *exchange.StreamBody downstream instead of buffering the whole file — required for large files.
  • Param surface canonicalisation. Repeated CreateEndpoint calls with the same directory + canonicalised param string return the same Endpoint. A different param set creates a new one.

Source

  • pkg/component/file/file.go — Component, Endpoint, fileParamDescriptors.
  • pkg/component/file/{producer,consumer}.go — write / poll engines.
  • pkg/component/file/{filter,sort,lock,lock_*}.go — filter, sort, read-lock strategies.
  • pkg/component/file/{idempotent,inflight,file_lang}.go — dedup, in-progress tracking, File-Language expressions.
  • pkg/component/file/streaming.go — stream=true body type.

See also