[{"data":1,"prerenderedAt":1233},["ShallowReactive",2],{"doc:\u002Fdocs\u002Fsftp":3,"docs-nav":1008},{"id":4,"title":5,"body":6,"description":999,"extension":1000,"meta":1001,"navigation":1003,"path":1004,"seo":1005,"stem":1006,"__hash__":1007},"docs\u002Fdocs\u002Fsftp.md","SFTP: files on a server, in and out",{"type":7,"value":8,"toc":984},"minimark",[9,13,22,40,53,58,113,128,133,144,151,179,190,193,197,204,369,405,412,434,447,458,462,468,540,543,547,568,575,645,659,678,692,704,708,738,925,929,950,954],[10,11,5],"h1",{"id":12},"sftp-files-on-a-server-in-and-out",[14,15,16,17,21],"p",{},"An ",[18,19,20],"strong",{},"SFTP connection"," reaches any SSH server that offers SFTP (OpenSSH, a NAS, a\nmanaged SFTP service). It does two things:",[23,24,25,33],"ul",{},[26,27,28,29,32],"li",{},"a datasource ",[18,30,31],{},"«SFTP folder»"," reads the files of a folder that match a glob,\nstacks them into one table and keeps it as a snapshot, refreshed by hand or on a\nschedule like every other database datasource;",[26,34,35,36,39],{},"an Output node with destination ",[18,37,38],{},"SFTP server"," writes the result of a flow as a\nfile in a folder of the server.",[14,41,42,43,46,47,52],{},"Like the other connections it lives in a folder and needs ",[18,44,45],{},"CONNECT"," on that folder\nto be created, tested and used. Any host may be reached, as for databases: CONNECT is\nthe barrier, so give it to the people who may move data to and from that server. The\nother ways data comes in are listed in ",[48,49,51],"a",{"href":50},"\u002Fdocs\u002Fsources","Sources",".",[54,55,57],"h2",{"id":56},"the-connection","The connection",[59,60,61,74],"table",{},[62,63,64],"thead",{},[65,66,67,71],"tr",{},[68,69,70],"th",{},"Field",[68,72,73],{},"Meaning",[75,76,77,90,98],"tbody",{},[65,78,79,83],{},[80,81,82],"td",{},"Host, port",[80,84,85,86,52],{},"The SSH server; the port defaults to 22. Host name or IP only, no ",[87,88,89],"code",{},"sftp:\u002F\u002F",[65,91,92,95],{},[80,93,94],{},"Username",[80,96,97],{},"The SSH account.",[65,99,100,103],{},[80,101,102],{},"Sign in with",[80,104,105,108,109,112],{},[18,106,107],{},"Password",", or ",[18,110,111],{},"Private key",": a PEM or OpenSSH private key (Ed25519, ECDSA or RSA) with its passphrase if it has one.",[14,114,115,116,119,120,123,124,127],{},"The password, or the private key together with its passphrase, is encrypted at rest\nwith the same Fernet key as every other connection secret (",[87,117,118],{},"SECURITY__FERNET_KEY","),\ntravels encrypted to the worker and is decrypted only to authenticate. The API never\nreturns it: ",[87,121,122],{},"has_password"," and ",[87,125,126],{},"has_private_key"," say whether one is stored. Only the\nsecret of the chosen method is offered to the server.",[129,130,132],"h3",{"id":131},"the-host-key-trust-on-first-use","The host key: trust on first use",[14,134,135,136,139,140,143],{},"SSH has no certificate authority: what proves the server is the right one is its\n",[18,137,138],{},"host key",". The connection keeps the key's type and SHA256 fingerprint, the one\n",[87,141,142],{},"ssh-keygen -lf \u002Fetc\u002Fssh\u002Fssh_host_ed25519_key.pub"," prints on the server.",[14,145,146,147,150],{},"Accepting a key takes two steps, and ",[18,148,149],{},"no credential is ever sent to a key that is\nnot accepted",":",[152,153,154,169],"ol",{},[26,155,156,159,160,164,165,168],{},[18,157,158],{},"«Test connection»"," reads the key the server offers. If it is not the accepted\none — never accepted, or different — the connection is closed ",[161,162,163],"em",{},"before"," any\npassword or key signature is sent, and the form shows the key (",[87,166,167],{},"ssh-ed25519 SHA256:…","), with the previous one and a warning when it changed. Compare it with\nthe fingerprint the server's administrator gives you.",[26,170,171,174,175,178],{},[18,172,173],{},"«Accept this key and test»"," tests again naming that key: the credentials are\nsent only if the server still offers exactly it. On a saved connection the key is\nthen stored, with a ",[87,176,177],{},"connection.host_key_accept"," line in the audit log (and the\nprevious fingerprint); in the form of a new connection it is stored on save, by\nthe same named test against the saved connection.",[14,180,181,182,185,186,189],{},"A test of a connection whose accepted key the server presents checks the credentials\nas usual. ",[18,183,184],{},"Every other connection"," — the file list of the datasource form, every\nimport, every Output — checks the key before sending any credential. A connection\nnever accepted is refused; a different key (of the same type or of another) is\nrefused with ",[161,187,188],{},"«The host key of host:port has changed … run «Test connection» again to\naccept the new key»",", translated in the interface. Nothing was sent to the server.\nChanging the host or the port of a connection forgets the accepted key: another\naddress is another server until a test says which key it has. Changing the host, the\nport or the user needs the password (or the private key) typed again: a stored secret\nnever follows a connection to another server or account, and a test before saving\nonly ever uses the secret typed in the form.",[14,191,192],{},"A server has one key per type (Ed25519, ECDSA, RSA). Once a key is accepted the\nclient asks for that type, so an upgrade that changes which type is preferred does\nnot read as a changed key; a server that no longer has a key of that type reads as a\nchanged key, like any other.",[54,194,196],{"id":195},"datasource-sftp-folder","Datasource «SFTP folder»",[14,198,199,200,203],{},"From a folder: ",[18,201,202],{},"New → Datasource from a database",", choose the SFTP connection, then:",[59,205,206,214],{},[62,207,208],{},[65,209,210,212],{},[68,211,70],{},[68,213,73],{},[75,215,216,228,263,307,315,323,347],{},[65,217,218,221],{},[80,219,220],{},"Folder on the server",[80,222,223,224,227],{},"Absolute (",[87,225,226],{},"\u002Fupload\u002Fvendite","), or relative to the login folder; empty = the login folder. It must exist.",[65,229,230,233],{},[80,231,232],{},"Files",[80,234,235,236,239,240,123,243,246,247,250,251,254,255,258,259,262],{},"A name or a glob: ",[87,237,238],{},"vendite_*.csv","; ",[87,241,242],{},"*",[87,244,245],{},"?"," within a name, ",[87,248,249],{},"**"," for any subfolder (",[87,252,253],{},"**\u002F*.csv","; links to folders are not followed). Case-sensitive. ",[87,256,257],{},".."," is refused, in the folder too. ",[18,260,261],{},"Check files"," lists what it takes.",[65,264,265,268],{},[80,266,267],{},"Format",[80,269,270,273,274,277,278,277,281,284,285,277,288,284,291,277,294,277,297,284,300,277,303,306],{},[161,271,272],{},"From each file's extension"," (",[87,275,276],{},".csv"," ",[87,279,280],{},".txt",[87,282,283],{},".tsv",", ",[87,286,287],{},".parquet",[87,289,290],{},".pq",[87,292,293],{},".xlsx",[87,295,296],{},".xlsm",[87,298,299],{},".xls",[87,301,302],{},".ndjson",[87,304,305],{},".jsonl",": a glob may mix them; any other extension refuses the import), or CSV, Parquet, Excel, NDJSON for every file.",[65,308,309,312],{},[80,310,311],{},"CSV separator, encoding, header",[80,313,314],{},"The reading options of the file sources: one-character separator; UTF-8, UTF-8 with invalid bytes replaced, or Windows-1252; whether the first row is the header.",[65,316,317,320],{},[80,318,319],{},"Excel sheet",[80,321,322],{},"Empty = the first sheet of the workbook, hidden or not. After «Check the files» the field becomes a list of the sheets of the first workbook found (one of 50 MB at most is downloaded for it), the hidden ones marked.",[65,324,325,328],{},[80,326,327],{},"Time zone, variables, initial last refresh",[80,329,330,331,335,336,284,339,342,343,346],{},"Folder and files may hold ",[48,332,334],{"href":333},"\u002Fdocs\u002Fplaceholders","placeholders"," — ",[87,337,338],{},"sales_{yesterday:yyyyMMdd}.csv",[87,340,341],{},"in\u002F{day}"," — and the datasource's list and range variables (",[87,344,345],{},"day = today-7 .. today step 1d",").",[65,348,349,352],{},[80,350,351],{},"Refresh",[80,353,354,357,358,361,362,284,365,368],{},[18,355,356],{},"Snapshot"," (the table is rebuilt), or ",[18,359,360],{},"append by key",": the rows whose key columns (",[87,363,364],{},"_param_day, id",[87,366,367],{},"_file","…) come again replace the old ones.",[14,370,371,372,375,376,379,380,382,383,108,386,389,390,392,393,396,397,400,401,404],{},"Every file that matches is read at ",[18,373,374],{},"every refresh"," and the rows are stacked into one\ntable, united by column name (a column missing in a file is empty there, and the\ndifference is logged). ",[18,377,378],{},"Every row says the file it comes from"," in the column\n",[87,381,367],{}," — always, a single matching file too — as its path below the folder\n(",[87,384,385],{},"vendite_01.csv",[87,387,388],{},"2026\u002Fq1\u002Fvendite.csv"," with ",[87,391,249],{},"), and ",[87,394,395],{},"_file_modified_at"," the\nfile's modification time (UTC). They are the last two columns, as on the SharePoint\ndatasource. Hidden files (",[87,398,399],{},".name",") and Office lock files (",[87,402,403],{},"~$name",") are skipped.",[14,406,407,408,411],{},"The files are ",[18,409,410],{},"left on the server",": the datasource only reads.",[14,413,414,415,419,420,423,424,426,427,429,430,433],{},"With placeholders or variables the folder and the files are expanded once per value\n(see ",[48,416,418],{"href":417},"\u002Fdocs\u002Fplaceholders#files-one-expansion-per-value","placeholders.md","): every file is\nread once, ",[87,421,422],{},"_param_\u003Cname>"," says the values on every row, a value without its file is\nskipped and listed in the run, and no file at all across the values fails the refresh.\nWith a dated folder (",[87,425,341],{},"), ",[87,428,367],{}," is the path below the fixed part (",[87,431,432],{},"in","), and\na day whose folder does not exist is a value without a file; a fixed folder must\nexist, as before.",[14,435,436,437,440,441,443,444,446],{},"The files must be ",[18,438,439],{},"machine readable",", the same contract as SharePoint: the header in\nthe first row, one name per column, no name twice (case-insensitive), no ",[87,442,367],{}," or\n",[87,445,395],{}," among them. A file with a title above the table, an empty column\nname or a repeated one is refused, naming the file — fix it at the source.",[14,448,449,450,453,454,457],{},"The import reports its progress as the other imports do (file ",[161,451,452],{},"i"," of ",[161,455,456],{},"n",", rows read,\nsaving). Database datasource rules apply: snapshot swap at success, one refresh at a\ntime, scheduled refresh, data contract, no sort keys (rows keep the files' order).",[129,459,461],{"id":460},"caps","Caps",[14,463,464,465,150],{},"A glob gone wrong must not download a whole server. Engine settings (backend and\nworkers), checked ",[18,466,467],{},"before anything is downloaded",[59,469,470,482],{},[62,471,472],{},[65,473,474,477,480],{},[68,475,476],{},"Variable",[68,478,479],{},"Default",[68,481,73],{},[75,483,484,501,514,527],{},[65,485,486,491,494],{},[80,487,488],{},[87,489,490],{},"SFTP__MAX_FILE_BYTES",[80,492,493],{},"536870912 (512 MB)",[80,495,496,497,500],{},"Size of one file. Every file is downloaded to the worker's ",[87,498,499],{},"\u002Ftmp"," and read in memory to be stacked, so it is also a memory bound.",[65,502,503,508,511],{},[80,504,505],{},[87,506,507],{},"SFTP__MAX_FILES",[80,509,510],{},"500",[80,512,513],{},"Files read by one refresh.",[65,515,516,521,524],{},[80,517,518],{},[87,519,520],{},"SFTP__MAX_TOTAL_BYTES",[80,522,523],{},"2147483648 (2 GB)",[80,525,526],{},"All the matching files together.",[65,528,529,534,537],{},[80,530,531],{},[87,532,533],{},"SFTP__TIMEOUT_SECONDS",[80,535,536],{},"30",[80,538,539],{},"Connection, SSH handshake, and every answer of the server after the login: a server that stops answering fails the import or the Output instead of holding a worker.",[14,541,542],{},"A glob also stops after walking 2000 folders.",[54,544,546],{"id":545},"output-to-an-sftp-server","Output to an SFTP server",[14,548,549,550,553,554,556,557,284,560,563,564,567],{},"On an Output node choose the destination ",[18,551,552],{},"SFTP server (file)",", then the connection,\nthe folder (no ",[87,555,257],{},"; empty = the login folder), the file name, the format —\n",[18,558,559],{},"CSV",[18,561,562],{},"Parquet"," or ",[18,565,566],{},"Excel"," — and the node's time zone (empty = UTC).",[14,569,570,571,574],{},"Folder and file name are templates in the ",[48,572,573],{"href":333},"placeholder language",",\nwith four names of the Outputs:",[59,576,577,587],{},[62,578,579],{},[65,580,581,584],{},[68,582,583],{},"Placeholder",[68,585,586],{},"Becomes",[75,588,589,602,614,624],{},[65,590,591,596],{},[80,592,593],{},[87,594,595],{},"{date}",[80,597,598,601],{},[87,599,600],{},"2026-10-17"," (in the node's zone, UTC by default, when the file is written)",[65,603,604,609],{},[80,605,606],{},[87,607,608],{},"{datetime}",[80,610,611],{},[87,612,613],{},"2026-10-17_143005",[65,615,616,621],{},[80,617,618],{},[87,619,620],{},"{run_id}",[80,622,623],{},"the run's number, the one in the run history",[65,625,626,631],{},[80,627,628],{},[87,629,630],{},"{flow}",[80,632,633,634,284,636,123,639,642,643],{},"the flow's name, with anything but letters, digits, ",[87,635,52],{},[87,637,638],{},"-",[87,640,641],{},"_"," turned into ",[87,644,641],{},[14,646,647,648,651,652,284,655,658],{},"and the whole grammar on top: ",[87,649,650],{},"export_{yesterday:yyyyMMdd}.csv",",\n",[87,653,654],{},"{flow}_{now:yyyy-MM-dd_HHmm}",[87,656,657],{},"\u002Foutbox\u002F{today:yyyy}\u002F{today:MM}",". A name written\nwith the four names above before the language existed is written with the same bytes.\nThe form shows the resolved name while you type, and the run is refused before it\nstarts if a template cannot be resolved.",[14,660,661,662,665,666,669,670,673,674,677],{},"A folder ",[18,663,664],{},"without"," placeholders must exist; a ",[18,667,668],{},"dated"," folder is created the first\ntime (its missing levels). The format's extension is added when missing; a name that\nends in another data format's extension (",[87,671,672],{},"report.parquet"," with format CSV) is refused,\nas is a name with a folder in it — written in the name or put there by a value\n(",[87,675,676],{},"{today:yyyy\u002FMM}"," belongs in the folder).",[14,679,680,683,684,687,688,691],{},[18,681,682],{},"The write is atomic for readers."," The file is uploaded under a hidden temporary name\nin the same folder (",[87,685,686],{},".name.\u003Crandom>.tmp",") and then renamed onto the final name with\nthe OpenSSH ",[87,689,690],{},"posix-rename"," extension, which replaces an existing file in one step;\nwhoever polls the folder never reads half a file. A server that says it does not\nsupport that extension gets the plain SFTP rename after removing the old file: a\nmoment without the file, never half a file. Any other failure of the rename leaves\nthe existing file as it is. If anything fails, the temporary file is removed and the run fails\nwith the reason.",[14,693,694,695,698,699,563,701,703],{},"An existing file with the final name is ",[18,696,697],{},"replaced",": use ",[87,700,595],{},[87,702,620],{}," to\nkeep one file per run. The run records what it wrote (host, path, bytes) in its\ndestination, shown when the run ends. CSV is streamed; Excel holds at most 1,048,575\nrows. Scheduled runs and orchestrations use the same Output: nothing else to set up.",[54,705,707],{"id":706},"example-the-depots-daily-sales-files","Example: the depots' daily sales files",[14,709,710,711,714,715,284,718,721,722,284,725,651,728,284,731,284,734,737],{},"Each depot drops a CSV a day on an SFTP server, in ",[87,712,713],{},"upload\u002Fdepots",":\n",[87,716,717],{},"sales_20261020.csv",[87,719,720],{},"sales_20261021.csv",", … with the columns ",[87,723,724],{},"data",[87,726,727],{},"deposito",[87,729,730],{},"canale",[87,732,733],{},"ordini",[87,735,736],{},"ricavo",". The sales office wants them as one table, and the monthly\nmargin back on the same server.",[152,739,740,772,808,852,886],{},[26,741,742,745,746,749,750,753,754,757,758,761,762,765,766,284,769,771],{},[18,743,744],{},"The connection."," In a folder where you have CONNECT, ",[18,747,748],{},"New → New connection",",\ntype ",[18,751,752],{},"SFTP (files)",": name ",[87,755,756],{},"Depots exchange (SFTP)",", host ",[87,759,760],{},"sftp.example.com",", port\n",[87,763,764],{},"2222"," (the server's; empty means 22), user ",[87,767,768],{},"tabularia",[18,770,102],{}," Password and\nthe password.",[26,773,774,777,778,780,781,783,784,787,788,791,792,52,795,798,803,805],{},[18,775,776],{},"Test connection."," The form shows the key the server offers,\n",[87,779,167],{},", and says that nothing has been sent yet. Compare the\nfingerprint with the one the server's administrator gives you\n(",[87,782,142],{}," on the server), then ",[18,785,786],{},"Accept this\nkey and test",": ",[161,789,790],{},"Connection works",". ",[18,793,794],{},"Create",[796,797],"br",{},[799,800],"img",{"alt":801,"src":802},"The SFTP connection form after Test connection: the server's ed25519 key and its fingerprint, with Accept this key and test","\u002Fmedia\u002Fguide\u002Fconnections\u002Fsftp-host-key.png",[796,804],{},[161,806,807],{},"The first test reads the server's key and stops there: the password is sent only after you accept that key.",[26,809,810,813,814,284,817,820,821,823,824,284,827,277,830,284,832,277,834,837,838,840,841,843,847,849],{},[18,811,812],{},"The datasource."," In ",[87,815,816],{},"Sample \u002F Private tables",[18,818,819],{},"New → Datasource from a\ndatabase",", connection ",[87,822,756],{},", name ",[87,825,826],{},"depot_sales",[18,828,829],{},"Folder on the\nserver",[87,831,713],{},[18,833,232],{},[87,835,836],{},"sales_*.csv",", format from each file's extension.\n",[18,839,261],{}," lists the five files it will stack.",[796,842],{},[799,844],{"alt":845,"src":846},"The SFTP folder datasource: folder upload\u002Fdepots, files sales_*.csv, and Check files listing five files","\u002Fmedia\u002Fguide\u002Fsources\u002Fsftp-folder-datasource.png",[796,848],{},[161,850,851],{},"Check files: the glob takes five files, stacked into one table.",[26,853,854,857,858,273,860,862,863,865,866,284,869,872,873,875,879,881],{},[18,855,856],{},"Create & import."," The datasource has 125 rows and seven columns: the five of the\nfiles, then ",[87,859,367],{},[87,861,717],{},", …) and ",[87,864,395],{},". Schedule it\n(",[18,867,868],{},"Schedule automatic refresh (cron)",[87,870,871],{},"30 6 * * *","): every morning it reads the\nfiles again, the new one included.",[796,874],{},[799,876],{"alt":877,"src":878},"depot_sales in the Viewer: the columns of the files, then _file and _file_modified_at on every row","\u002Fmedia\u002Fguide\u002Fsources\u002Fsftp-depot-sales-viewer.png",[796,880],{},[161,882,883,885],{},[87,884,826],{}," in the Viewer: every row says which file it came from.",[26,887,888,891,892,894,895,898,899,902,903,906,907,284,910,913,914,916,920,922],{},[18,889,890],{},"The way back."," In the flow «Margin by Category and Month», an Output node with\ndestination ",[18,893,552],{},", the same connection, folder\n",[87,896,897],{},"outbox\u002F{today:yyyy}\u002F{today:MM}",", file name ",[87,900,901],{},"margin_{yesterday:yyyyMMdd}",", format CSV,\ntime zone ",[87,904,905],{},"Europe\u002FRome",". Under each field the form shows what a run would write today\n(",[87,908,909],{},"outbox\u002F2026\u002F10",[87,911,912],{},"margin_20261027","); the dated folder is created on the first run.",[796,915],{},[799,917],{"alt":918,"src":919},"The SFTP Output node with the dated folder and file name and, under each, the resolved value","\u002Fmedia\u002Fguide\u002Fplaceholders\u002Fsftp-output-placeholders.png",[796,921],{},[161,923,924],{},"The Output's templates and what they give on 28 October 2026.",[54,926,928],{"id":927},"lineage-dbt","Lineage, dbt",[14,930,931,932,935,936,939,940,935,942,945,946,949],{},"OpenLineage: an SFTP refresh reads ",[87,933,934],{},"sftp:\u002F\u002Fhost:port"," + ",[87,937,938],{},"\u002Ffolder\u002Fglob"," (the templates as written); an SFTP Output\nis one dataset, ",[87,941,934],{},[87,943,944],{},"\u002Ffolder\u002F\u003Cfile-name template>",", whatever file each\nrun writes — the file a run wrote is the dataset's version (",[87,947,948],{},"datasetVersion"," facet). The dbt export turns an SFTP datasource\ninto a seed (like SharePoint) and an SFTP Output into a table model. The Lineage page\nshows the file an Output writes.",[54,951,953],{"id":952},"proofs","Proofs",[14,955,956,959,960,963,964,967,968,971,972,975,976,979,980,983],{},[87,957,958],{},"backend\u002Ftests\u002Ftest_sftp.py"," runs against an SFTP server inside the test process\n(",[87,961,962],{},"backend\u002Ftests\u002Ffake_sftp.py",", paramiko's server classes); the gateway's part is in\n",[87,965,966],{},"gateway\u002Ftests\u002Ftest_sftp_*.py",". Against a real OpenSSH server (a throwaway\n",[87,969,970],{},"lscr.io\u002Flinuxserver\u002Fopenssh-server"," container on the stack's network):\n",[87,973,974],{},"e2e\u002Fsftp\u002Fengine_proofs.py"," (engine), ",[87,977,978],{},"e2e\u002Fsftp\u002Fapi_proofs.py"," (the API end to end,\nincluding a key change) and ",[87,981,982],{},"e2e\u002Fsftp\u002Fbrowser_forms.py"," (the three forms in Firefox).",{"title":985,"searchDepth":986,"depth":987,"links":988},"",2,3,[989,992,995,996,997,998],{"id":56,"depth":986,"text":57,"children":990},[991],{"id":131,"depth":987,"text":132},{"id":195,"depth":986,"text":196,"children":993},[994],{"id":460,"depth":987,"text":461},{"id":545,"depth":986,"text":546},{"id":706,"depth":986,"text":707},{"id":927,"depth":986,"text":928},{"id":952,"depth":986,"text":953},"An SFTP connection reaches any SSH server that offers SFTP (OpenSSH, a NAS, a\nmanaged SFTP service). It does two things:","md",{"source":1002},"docs\u002Fsftp.md",true,"\u002Fdocs\u002Fsftp",{"title":5,"description":999},"docs\u002Fsftp","7T2e4vh-RMsyd9NE4x-jrXjNlVOqcyKptqZN6Kjyqe8",[1009,1028,1083,1112,1144,1173,1199,1225],{"title":1010,"icon":1011,"intro":1012,"items":1013},"Getting started","start","Install it on one machine, learn the few ideas everything else is built on, and run a first flow.",[1014,1016,1019,1022,1025],{"path":1015,"title":1010},"\u002Fdocs\u002Fgetting-started",{"path":1017,"title":1018},"\u002Fdocs\u002Fgetting-started-docker-compose","Walkthrough with Docker Compose",{"path":1020,"title":1021},"\u002Fdocs\u002Fdeploy\u002Fminikube","Try it on your computer (minikube)",{"path":1023,"title":1024},"\u002Fdocs\u002Fconcepts","Concepts",{"path":1026,"title":1027},"\u002Fdocs\u002Foverview","Overview (README)",{"title":1029,"icon":1030,"intro":1031,"items":1032},"Capabilities","capabilities","What you can build: visual flows, analysis on any step, AI questions, pixel-perfect reports, dashboards, Python, R and SQL scripts, containers and the orchestration that ties them together.",[1033,1036,1039,1042,1045,1048,1051,1054,1057,1060,1063,1066,1069,1072,1075,1077,1080],{"path":1034,"title":1035},"\u002Fdocs\u002Fcapabilities","All capabilities",{"path":1037,"title":1038},"\u002Fdocs\u002Fcapabilities\u002Fflows","Low-code flows",{"path":1040,"title":1041},"\u002Fdocs\u002Fcapabilities\u002Fpreview-and-analysis","Preview and analysis",{"path":1043,"title":1044},"\u002Fdocs\u002Fcapabilities\u002Fask-your-data","Ask your data with AI",{"path":1046,"title":1047},"\u002Fdocs\u002Fcapabilities\u002Freports","Pixel-perfect reports",{"path":1049,"title":1050},"\u002Fdocs\u002Fcapabilities\u002Freport-functions","Report functions",{"path":1052,"title":1053},"\u002Fdocs\u002Fcapabilities\u002Fdashboards","Dashboards",{"path":1055,"title":1056},"\u002Fdocs\u002Fscripting","Python and R",{"path":1058,"title":1059},"\u002Fdocs\u002Fsql-scripts","SQL scripts",{"path":1061,"title":1062},"\u002Fdocs\u002Fcapabilities\u002Fnotebooks","marimo notebooks as apps",{"path":1064,"title":1065},"\u002Fdocs\u002Fcontainer-node","Docker images in flows",{"path":1067,"title":1068},"\u002Fdocs\u002Fcapabilities\u002Fflow-groups","Flow groups: orchestration",{"path":1070,"title":1071},"\u002Fdocs\u002Fcapabilities\u002Fscheduling","Scheduling",{"path":1073,"title":1074},"\u002Fdocs\u002Fpushmail","Pushmail: datasources, reports and dashboards by email",{"path":333,"title":1076},"Dynamic dates",{"path":1078,"title":1079},"\u002Fdocs\u002Fcapabilities\u002Fengines","Engines",{"path":1081,"title":1082},"\u002Fdocs\u002Fengines\u002Fengine-differences","Engine differences",{"title":51,"icon":1084,"intro":1085,"items":1086},"sources","Every way data comes in: files, databases, buckets, SFTP folders, HTTP APIs, SharePoint, Google Sheets, and the results of your own flows.",[1087,1089,1092,1095,1098,1100,1103,1106,1109],{"path":50,"title":1088},"All sources",{"path":1090,"title":1091},"\u002Fdocs\u002Fsources\u002Ffiles","Uploaded files",{"path":1093,"title":1094},"\u002Fdocs\u002Fsources\u002Fdatabases","Database tables and queries",{"path":1096,"title":1097},"\u002Fdocs\u002Fs3-datasource","S3 buckets",{"path":1004,"title":1099},"SFTP folders",{"path":1101,"title":1102},"\u002Fdocs\u002Fapi-datasource","HTTP APIs",{"path":1104,"title":1105},"\u002Fdocs\u002Fsources\u002Fsharepoint","Excel on SharePoint",{"path":1107,"title":1108},"\u002Fdocs\u002Fsources\u002Fgoogle-sheets","Google Sheets",{"path":1110,"title":1111},"\u002Fdocs\u002Fsources\u002Fflow-outputs","Results of flows and scripts",{"title":1113,"icon":1114,"intro":1115,"items":1116},"Connections","connections","The systems Tabularia reads from and writes to, how each connection is set up, and who may use it.",[1117,1120,1123,1126,1129,1131,1132,1134,1135,1138,1141],{"path":1118,"title":1119},"\u002Fdocs\u002Fconnections","All connections",{"path":1121,"title":1122},"\u002Fdocs\u002Fconnections\u002Fdatabases","Databases",{"path":1124,"title":1125},"\u002Fdocs\u002Fsqlserver","Microsoft SQL Server driver",{"path":1127,"title":1128},"\u002Fdocs\u002Fconnections\u002Fs3","S3 and compatible storage",{"path":1004,"title":1130},"SFTP servers",{"path":1101,"title":1102},{"path":1104,"title":1133},"SharePoint",{"path":1107,"title":1108},{"path":1136,"title":1137},"\u002Fdocs\u002Fconnections\u002Fsmtp","SMTP email",{"path":1139,"title":1140},"\u002Fdocs\u002Fcontainer-registries","Container registries",{"path":1142,"title":1143},"\u002Fdocs\u002Fconnections\u002Fdestinations","Writing data out",{"title":1145,"icon":1146,"intro":1147,"items":1148},"Integrations","integrations","How Tabularia fits your stack: AI providers, the REST API and webhooks, dbt, OpenLineage, single sign-on, SIEM and monitoring.",[1149,1152,1155,1158,1161,1164,1167,1170],{"path":1150,"title":1151},"\u002Fdocs\u002Fintegrations","All integrations",{"path":1153,"title":1154},"\u002Fdocs\u002Fintegrations\u002Fai","AI: where it is used",{"path":1156,"title":1157},"\u002Fdocs\u002Fapi","API, tokens and webhooks",{"path":1159,"title":1160},"\u002Fdocs\u002Fdbt-export","Export to dbt",{"path":1162,"title":1163},"\u002Fdocs\u002Fopenlineage","OpenLineage",{"path":1165,"title":1166},"\u002Fdocs\u002Fsso-keycloak","Single sign-on with Keycloak",{"path":1168,"title":1169},"\u002Fdocs\u002Fsiem-splunk","Audit log to Splunk",{"path":1171,"title":1172},"\u002Fdocs\u002Fintegrations\u002Fmonitoring","Monitoring",{"title":1174,"icon":1175,"intro":1176,"items":1177},"Security & governance","governance","Who may see and do what, what is recorded, and how data quality and personal data are kept in check.",[1178,1181,1184,1187,1190,1193,1196],{"path":1179,"title":1180},"\u002Fdocs\u002Fgovernance","Overview",{"path":1182,"title":1183},"\u002Fdocs\u002Fgovernance\u002Fpermissions","Permissions",{"path":1185,"title":1186},"\u002Fdocs\u002Fgovernance\u002Faudit-log","Audit log",{"path":1188,"title":1189},"\u002Fdocs\u002Fgovernance\u002Fdata-contracts","Data contracts",{"path":1191,"title":1192},"\u002Fdocs\u002Fdesign\u002Fsso-group-mapping","SSO and group mapping",{"path":1194,"title":1195},"\u002Fdocs\u002Fexamples\u002Fkeycloak","Keycloak example on a laptop",{"path":1197,"title":1198},"\u002Fdocs\u002Fengines\u002Fclickhouse-ai-user","A ClickHouse user for the AI assistant",{"title":1200,"icon":1201,"intro":1202,"items":1203},"Install & operate","operate","Run it in production on Kubernetes, configure it, upgrade it and keep it healthy.",[1204,1207,1210,1213,1216,1219,1222],{"path":1205,"title":1206},"\u002Fdocs\u002Fdeploy\u002Fkubernetes","Kubernetes and Helm",{"path":1208,"title":1209},"\u002Fdocs\u002Fdeploy\u002Fkind","A company-like cluster on one computer (kind)",{"path":1211,"title":1212},"\u002Fdocs\u002Fdeploy\u002Fupgrading","Upgrading, backups and restore",{"path":1214,"title":1215},"\u002Fdocs\u002Fdeploy\u002Frelease-checklist","Install and upgrade checklist",{"path":1217,"title":1218},"\u002Fdocs\u002Fconfiguration","Configuration reference",{"path":1220,"title":1221},"\u002Fdocs\u002Fengine-settings","Settings from the panel",{"path":1223,"title":1224},"\u002Fdocs\u002Fdatabase-migrations","Database migrations",{"title":1226,"icon":1227,"intro":1228,"items":1229},"Reference","reference","Release process and the remaining reference pages.",[1230],{"path":1231,"title":1232},"\u002Fdocs\u002Frelease-process","Release process",1793656371838]