DuckDB sidekickA DuckDB, Parquet, delimited-text, and Excel data viewer for Visual Studio Code: read-only unless you turn on Allow Changes for a DuckDB file. Open a Features
Source files are never modified unless you turn on Allow Changes for that file: then SQL you run changes a DuckDB file, and Save overwrites a CSV, Excel, or Parquet file. Explorer context menuRight-clicking a Save as DuckDB appears on the same files and on
Table names keep letters of any script, so a Thai sheet name stays Thai;
anything else becomes Remote repositoriesThe viewer supports files opened through VS Code Remote - SSH, WSL, Dev Containers, Codespaces, and desktop virtual workspaces such as Remote Repositories. Install the extension in the location offered by VS Code, then open the data file normally or use Open With. For a virtual repository, the extension reads the resource through VS Code and opens a disposable local snapshot with DuckDB. The snapshot is refreshed when the source changes and removed when the viewer closes. Read-only repositories still support viewing, SQL, profiles, and CSV or DuckDB export to a separate writable location. Notebook export requires a local source because the exported notebook must
reopen the data file outside VS Code. The Opening a file from a linkPK DuckDB: Open URL…, or the link button beside the file name in a viewer's toolbar, downloads a data file from a shared link and opens it in the viewer for its kind:
The box offers the link on your clipboard when there is one. It takes links from:
Nothing is downloaded until you ask, and only from the link you gave. A link that isn't shared publicly gets a message saying how to share it on that service, followed by every address tried and what each one answered. A CSV saved in UTF-16, or in your computer's legacy code page such as Windows-874 for Thai, is converted to UTF-8 as it is downloaded. The tab is named after the file. The file stays read-only (Allow Changes needs a file on disk) and cannot be exported as a notebook, which would need to reopen it outside VS Code. PK DuckDB: Reload from Link downloads it again, and every viewer on it shows the new copy. Downloads are kept in the extension's storage, so a tab reopened after a restart shows the last copy without going online. A copy nobody has opened for 30 days is removed. Grid interactionClick a column header to sort it. Repeated clicks cycle through ascending,
descending, and the relation's original browsing order; ▲ or ▼ beside the
column name shows the active direction. Each table or query result remembers
its own sort while you switch tabs. Table pages are sorted by DuckDB, with
Clicking a header also selects it. Shift+click selects a contiguous header range, Ctrl/Cmd+click toggles one row or column, and Ctrl/Cmd+Shift+click adds a range without changing the sort. Right-click selects without sorting. The top-left corner or Ctrl/Cmd+A selects all displayed cells; Escape or an empty grid click clears the selection. Focus the grid and use arrows, Home, End, Page Up, Page Down, Tab, Enter, and their Shift or Ctrl/Cmd variants for Excel-style movement and range extension. Ctrl/Cmd+Space selects the active column, Shift+Space the active row, and both modifiers select all cells. After selecting a whole row or column, Shift+arrow extends or shrinks that selection along its axis; add Ctrl/Cmd to jump to the edge. Tail 10 switches to the final ten rows in the current sort order; Show all restores the full relation. Ctrl/Cmd+C copies a rectangular cell range or one or more selected rows or columns as TSV. Whole columns include their headers and all rows, including uncached table pages. Ctrl/Cmd+Shift+C prepends column headers to selected rows. Tabs, line breaks, and quotes are escaped, while nulls remain empty and values keep their exact raw text rather than display-only formatting. The right-click menu labels the active operation as Copy Cell, Cells, Row(s), Column(s), or All Cells. Right-clicking the top-left corner selects the entire displayed grid and opens that menu. The same selection and copy behavior works in frozen panes. Right-clicking inside the SQL editor keeps its editor menu. Drag the right edge of a header to resize that column, down to a minimum of 40px. Double-click the edge to fit that column to its widest cached or displayed value, capped at 400px. Auto-fit all applies the same measurement to every column. Focus Cell highlights the active row and column, including their headers. While it is on, Column colors is turned off and disabled so the two background treatments do not compete. Leaving Focus Cell restores Column colors to exactly the setting it had before, whether that setting was on or off. Filtering rowsPoint at a column header and click its funnel to filter that column. Text and other columns list their most frequent values with how many rows hold each; tick the ones to keep. Type in Contains… to narrow the list, which also finds values past the most frequent ones; tick Every value containing … to keep all of them at once, matched without regard to case. Number and date columns take a From and To instead, either of which can be left open; a range never keeps an empty cell. Clear filter removes that column's filter. Filters on several columns combine: a row must pass all of them. A filtered
column's funnel stays lit, and a strip above the grid shows how many rows are
left (
Fixing a columnRight-click a cell or a column header and point at Fix. The fixes act on the column you clicked, or on every selected column when whole columns are selected:
Before anything changes, a confirmation says how many rows would change, shows a few values as they are and as they would be, and names any value that could not be converted. A fix that would change nothing just says so. Each fix applies to every row of the table, not only the rows a filter shows, and the confirmation says so when the grid is filtered. Fixes build on one another; Fix ▸ Revert to Original Data undoes all of them together. Fixes work on table tabs, not on a query result. The fixed rows live in the viewer: the grid, filters, profile, charts, search, and exports all see them, and so does the SQL editor for a CSV, Excel, or Parquet file's own tabs. A DuckDB file's table, or a table added from another file, keeps its own name in SQL, so there the editor still reads the original. The file is not changed, and fixes are gone when it is reopened — unless you save them. Find & ReplaceRight-click a cell or a column header and choose Find & Replace…. A bar like VS Code's find widget opens over the grid, on that column; its drop-down picks another.
A replacement is a fix: Fix ▸ Revert to Original Data undoes it, and the file is not changed. The column comes out as text. Setting a column's typeRight-click a cell or a column header and point at Set Column Type to read
that column as VARCHAR, BIGINT, INTEGER, DOUBLE, DECIMAL(18,2), BOOLEAN, DATE,
TIMESTAMP, TIMESTAMPTZ, or TIME; its current type is ticked. When some values
cannot be read as the new type, you are told how many and asked first; they
become empty. Reading a number or text as a date also understands Excel's date
serials, so Set Column Type ▸ Original Type puts the column back. On a tab that already shows fixed rows, a type change is one more fix, and Fix ▸ Revert to Original Data undoes it. The file is not changed, and the types are gone when it is reopened. For a CSV whose type should stick for the session, PK DuckDB: Configure Tabular Source still sets it as the file is read. Freeze panesSelect a cell and click Freeze panes. Everything above and to the left of it stays put while the rest of the grid scrolls, exactly as in Excel — so selecting the cell in row 3, column C pins the first two rows and the first two columns. The button then reads Unfreeze and removes the split; to move a split, unfreeze, select a new cell, and freeze again. Both actions are also available from the command palette as PK DuckDB: Freeze Panes at Active Cell and PK DuckDB: Unfreeze Panes. Selecting the very first cell freezes nothing, since there is nothing above or to its left. A split always leaves at least one row and one column free, so the grid can never be pinned solid. Each relation remembers its own split, so switching tabs and coming back keeps it. The split is never written to the source file, and it is dropped when the file changes on disk, because a relation's shape may have changed with it. One difference from Excel: columns you scroll past slide underneath the frozen ones rather than stopping beside them. Freezing the leftmost columns to keep an identifier in view works as expected; freezing many columns and then scrolling far right will hide some behind the frozen block. ThemeThe Theme toolbar button cycles the viewer through three states:
The two forced themes are built from the Okabe-Ito colorblind-safe palette, so nothing in the chrome — SQL syntax highlighting, the correlation chart, the explorer tree, status marks — rests on a red/green distinction. Text stays at WCAG AA contrast and other marks at 3:1. The choice is stored in the Number displayNumeric columns are right-aligned in the grid, and
Two different things are being removed. A A column whose values are too small for the cap widens instead of rounding to zero, and scientific notation is never used. The comma button in the toolbar toggles thousands separators for numeric cells:
Grouping is performed directly on the value's text, so integers larger than JavaScript's safe-number range keep every digit. The separator pass leaves exponent notation and non-numeric text unchanged.
All number formatting is display only. Ctrl/Cmd+C and the grid context menu copy exact stored values, hovering a cell shows the raw value, and CSV, Excel, and DuckDB exports are unaffected. ExplorerClick Explorer in the viewer toolbar to show or hide the tree of databases, schemas, tables, views, and columns. Selecting a table or view opens it in the grid and highlights its bottom tab, so the tree and the tabs stay in step. The tree is read from DuckDB's catalog, so expanding a table never scans it. Columns for a Parquet, delimited, or Excel source are read when the relation is first expanded, which keeps opening a many-sheet workbook fast. Generate DDLRight-click a database, schema, table, or view in the tree and choose
Generate DDL. The
Macros are not included, because DuckDB does not keep their parameter
defaults. A CSV, Excel, or Parquet file stores no DDL of its own, so for those
the viewer writes a Find in databaseClick Find in database in the toolbar, press Ctrl+Shift+H
(Cmd+Shift+H on macOS), or run PK DuckDB: Find in Database. Type a
value and press Enter. Every column of every tab is searched,
case-insensitively, for the text anywhere in the value. Numbers and dates match
by their text too, and Results appear table by table as they are found. Each column with a match
shows how many rows match. Click one to run a query in the SQL editor that
returns exactly those rows, and edit it from there. Stop ends a long
search, and a search never holds up your own SQL. Binary ( Click Data profile in the viewer toolbar to open a resizable pane beside the grid. It has three tabs:
Profiles are calculated lazily by DuckDB and cached for each relation until the
source file changes. The Query Result tab is also profileable: its successful
ChartsClick Chart in the viewer toolbar, or run PK DuckDB: Toggle Chart, to chart the active table. The panel is resized by dragging its bottom edge, and expanded out of the split altogether by the last icon over the chart — the rest of the viewer steps back behind it, and the same icon, Escape, or a click outside brings it back to the height you had left it at. Fifteen views are available:
Four filter slots above the controls narrow every view at once. Pick a column and either tick the values you want or type a range. All aggregation happens inside DuckDB and only the finished series is sent to
the chart, so charting does not load your data into memory. Where a
view would otherwise produce an unreadable chart it is bounded and says so: the
top categories are kept, and a scatter plots a random sample whose size is
reported next to the chart. The caps are configurable through the
A trend shows every interval between its first and its last, including the ones nothing happened in, so a quiet month is a gap in the line rather than a month the axis skips. Dates along the bottom are labelled the short way: "Jan" over "2000", then "Apr", "Jul", "Oct", with the year written only where it changes. Set a trend's Scale to Change since start to compare lines of very different sizes, the way stock prices are compared. Every line starts at 0% and shows its percent change from its own first value. Hover a point to see both the change and the actual value. A line that is zero throughout has nothing to measure a change from, so it is left off and the note under the chart says so. When a trend or a scatter carries more points than fit across the panel, a slider appears under it: drag the slider, or scroll and drag on the chart itself, to narrow the range. Changing any control resets it. CardsCard is the chart add-in's Bump chartsBump ranks an item column period by period, largest first, and joins each
item's places so a rise or fall shows as a bump and two items that swap places
cross — the chart add-in's PalettesCharts of several series are drawn in the viewer's own colour-blind-safe
palette, or in one of the XFN chart functions' palettes — Deep,
Okabe-Ito, Tableau, Muted, Pastel, Dark, Colorblind,
Viridis, Corporate, Earth, Bright, Teals, Burgundys or
Blacks. Set the default with Chart settingsSettings ▾ at the end of the chart tabs saves every chart's picks — each
tab's columns and options, its palette, and the panel's filters — to a JSON
file you choose, and loads them back: to return to a set of charts after the
file is closed, hand them to someone else, or draw the same charts over next
month's export. A table's charts load back onto that table where the file has
it, and onto the tab showing otherwise. A query's charts carry their query:
loading them puts it in the SQL editor and runs it — as a HistogramsA histogram is read on two scales: the count of values in each bar on the left, and the same heights as a proportion of every value counted on the right, so "how many" and "what share" are both read off one bar. A grouped histogram's proportions are of every group together, and hovering a bar gives its count and its share of that same total. The data profile's histograms carry the same two scales, as a share of the column's non-missing values. Box plotsThe whiskers stop at the furthest value still within 1.5 IQR of the box, and anything past that is drawn as its own small circle — the usual reading of a box plot, and the one that stops a single wild value from stretching a whisker until every box in the chart is squashed flat. The true minimum and maximum are still there: hover a box and it names them, along with how many values it holds and how many fell outside its whiskers. Show data gives the whiskers columns of their own beside them. Each group's size is written under its name, as With a grouping, Stats offers the test ggstatsplot prints over the boxes.
Test writes Welch's t with Hedges' g for two boxes, or Welch's ANOVA with
ω² for more, with the effect size's 95% interval and its size in a word —
A box with a very long tail draws the furthest outliers from each end rather
than all of them — 50 per box by default, through Boxes are grey, like the bars of a histogram: every box is the same measurement of the same column, so a colour would tell you nothing. The one you point at turns amber, which is what says which box you are reading. Tick Color each box to fill each group's box in its own colour from the chart's Palette instead. Inside a Facets grid, box plots keep their whiskers at the extremes and draw no outliers. A cell is a twelfth of the chart area, where a scatter of dots would be noise rather than a tail. BoxenplotsA Boxenplot is seaborn's letter-value plot, for the many rows a box plot handles worst: past a few thousand, 1.5 IQR marks hundreds of ordinary tail values as outliers. It draws the box plot's box, then a box half as wide out to the eighths, another to the sixteenths, and so on into the tails, each a shade paler, with the median across the widest and the mean as the red dot. What lies past the last box is drawn as a box plot's outliers are. Depth picks seaborn's rule for how far the boxes go — Tukey (the default), Proportion, Trustworthy, or Full, which reaches the minimum and maximum. Log draws it on a log axis, built from the logs of the values, so a long right tail no longer squashes every box into the floor; the dot is then the geometric mean, and the note says how many rows at or below zero were left out. Hover a box and it names the share of the values it holds. Color each box works here too: each group's boxes fade from its palette colour rather than from grey. A Facets grid offers boxenplots too, with no values drawn past the last box, as its box plots draw none. Reference linesDistribution takes any of Mean, Median and Quartiles at once — comparing them is the point, and a mean pulled away from a median is the whole story of a skew. Mean and median are on by default; the quartiles are left to be asked for. Because the median is the 50th percentile, asking for both still draws one median rather than stacking two lines on a spot. Comparison draws its line across the bars instead, at their mean, their median, both, or a number you type — off by default, a bar chart being read against its own bars. A box plot is offered none: it already draws its median, and its axis is the values themselves. A Pareto is offered none for the opposite reason: its axis is its categories, so a line down it would stand at no value at all. Both withdraw the control rather than showing it to no effect. Range marks the same three statistics on each row's own line, where they answer a different question — where a group sits inside its own spread, rather than where the whole chart's middle is. A quartile mark is withdrawn when the dots are already at Q1 and Q3, since it would be drawn on top of itself. Ticking Quartiles draws the median too, so the marks show 25%, 50% and 75%. Each line is told apart three ways — a colourblind-safe colour, a dash, and a weight — so four crossing one chart stay distinguishable to a reader who cannot separate the hues, and under a forced palette that drops colour entirely. Pareto, Bullet, Range and FacetsA Pareto ranks a column's total by category, largest first, with the running share of the whole climbing over it up a right-hand percentage axis and a dashed guide at 80% — dashed because 80% is a rule of thumb rather than anything your data said. Where the curve crosses the guide is how few categories account for most of the number. The shares are divided by the total over every category, including the ones the cap dropped, so a capped chart's last bar reads below 100% rather than claiming the cap was the whole. The bars say it too: the ones that carry the running share up to 80% — the crossing bar included — are drawn in a solid mid grey, and the tail behind them takes the fainter grey a histogram bar has. Hovering any bar turns it amber, as everywhere else in the panel. Where the 80% point lies off the right of a capped chart every bar drawn is inside it, and where there is no positive total to take a share of there is no 80% at all, so no bar is singled out and no guide is drawn. A Bullet gives each row a target of its own instead of one line across them all: the target is a wide quartered bar, the actual a narrower one centred inside it, and a green tick stands at the goal so it stays readable when the actual overshoots. Both columns are reduced by the same aggregate. Show as switches between the measured values and each row's share of its own target, which is what makes a small group that beat its quota comparable to a large one that missed. A Range draws one row per group with a dot at each end of its span — min–max, or the middle half between Q1 and Q3, which is what a single outlier stops min–max from showing. Unlike a box plot a single-value group is kept: a range of one value is a real answer, and it draws as one dot. Facets answers whether a shape holds in every slice without setting a filter, reading, changing it, and holding the last one in your head: the same chart drawn once per slice. Give it a value and a facet row, a facet column, or both. Nothing a cell draws is decided by that cell — the bins are measured once over the whole column, the categories are ranked once over every row, and every cell is given the same ceiling, so a taller bar means more wherever it is. An empty slice still gets its cell, because a gap in the grid is a fact about the data. A date is coarsened rather than truncated, through the Every control; anything else keeps the largest slices and gathers the rest into one quieter cell that says how many it stands for. The grid scrolls rather than squeezing its rows. Chart › Card turns the grid into a dashboard's KPI cards, a tile per slice: a green or magenta edge and arrow for up or down, a grey sparkline of the Date's latest 24 periods (each to its own scale), "Current month" and its value, and that value against the period before at the Period picked — a week against last week ("vs. PW"), a month against last month ("vs. PM") — or, with Compare › Previous year, the same period a year before ("vs. PY"), in percent and in units. Every tile covers the same periods; a sum's empty period is a zero, a mean's a gap, and a period before the data starts leaves a dash. A column whose name reads as a rate ( A whole-number column that holds codes rather than amounts — Relationship and Trend carry a Log toggle — one per axis on the scatter, one for the value axis on a trend. It is what a measure spread over orders of magnitude needs: revenue by customer or rows by table otherwise piles into the bottom of the frame under its own largest value. A log axis cannot place a value at or below zero, so where the data reaches there the axis is drawn linear and the note under the chart says why. No bar chart offers it: a bar is read from zero, and logging one would leave its length saying something its number does not. The scatter is also never pinned to zero, since a point sits at a value rather than measuring a length from an origin. Every chart also publishes its numbers as a table under Show data, which can be copied as TSV, and the chart itself can be saved next to your file. Hover the chart and four icons appear in its top corner — one saves a PNG, the next the same picture as a smaller lossless WebP, the next an SVG you can scale or restyle afterwards, and the last expands the chart over the whole viewer for a closer look; Save image in the footer is the same PNG for anyone who would rather not go looking. Either way the picture is captioned with what it shows, where it came from, anything you filtered, and the same note the panel was showing — so a chart of the top thirty categories still says so once it is pasted somewhere else. Under a high-contrast theme the table replaces the chart, since a canvas cannot follow a forced palette. SQL and notebook exportClick SQL in the viewer toolbar, enter one read-only query (or, with changes allowed, one statement that changes the file), and select Run or press Ctrl/Cmd+Enter. The editor shows line numbers, and the panel is resized by dragging its bottom edge. The viewer accepts result-producing statements such as
DuckDB extensionsBy default the viewer loads no DuckDB extension but the Excel one it ships
with, and downloads nothing. Turn on the
With the setting on, DuckDB also installs and loads a known extension by
itself the first time a query needs it, as the DuckDB CLI does, so the
Match CaseEvery file opens with text compared ignoring case, so It is DuckDB's With changes allowed, it reaches changes too:
Allowing changesThe lock button in the toolbar, or PK DuckDB: Allow Changes / Make Read-Only, lets the SQL editor change the open DuckDB file. (On a CSV, Excel, or Parquet file it allows Save instead.) It is off whenever a file is opened, and turning it on asks you to confirm. Every viewer on the same file follows it, and clicking it again makes the viewer read-only. With changes allowed, the SQL editor also runs
Saving a CSV, Excel, or Parquet fileA CSV, TSV, PSV, Excel, or Parquet file is read into a temporary database, so SQL never changes it. With changes allowed on one, a Save button appears beside the lock, and Save — the button, Ctrl/Cmd+S in the viewer, or PK DuckDB: Save Changes to File — overwrites the file with what its tabs show: every fix, replacement, and column type.
Suggestions appear as you type and can be requested with Ctrl+Space. What is
offered first depends on the clause: relations after PrettifyPrettify in the SQL panel, Shift+Alt+F in the editor, right-click in the editor, or PK DuckDB: Prettify SQL reformats the query in place:
Each clause starts a line. The first item stays on the clause's line and later
items — separated by a comma, or by Keywords and type names are uppercased. Identifiers, quoted identifiers, string literals, function names, and comments keep the spelling you gave them, and the caret stays with the token it was on. Expand SELECT *Shift+Alt+E in the editor, right-click in the editor, or PK DuckDB: Expand SELECT * writes each star in the statement out as the columns it stands for:
It works on the selection if there is one, otherwise on the statement the
caret is in, and nothing is run. Join LinesCtrl+J (Cmd+J on macOS) in the SQL editor joins the line the caret is on to
the one below it, or, with several lines selected, joins them all into one. The
first line's trailing spaces and the next line's indentation are dropped and
one space goes between them, so Select and delete linesCtrl+L (Cmd+L on macOS) selects the caret's whole line, line break included, as VS Code's Expand Line Selection does; press it again to take in the next line, and with a selection it widens to whole lines. Ctrl+U deletes from the caret back to the start of its line and Ctrl+K from the caret to its end; at the very start or end of a line the line break goes instead, joining the two lines, and with a selection both delete the selection. Ctrl+U and Ctrl+K are Ctrl on macOS too. One Undo puts the text back. In a SQL script notebook's cells these keys keep VS Code's own meanings. Alt+Up and Alt+Down (Option on macOS) move the caret's line, or every line the selection touches, one line up or down, as VS Code's Move Line Up and Move Line Down do; the selection moves with the lines, and one Undo puts them back. Shift+Alt+Down (Shift+Option on macOS) duplicates the caret's line, or every line the selection touches, below itself and moves the selection to the copy, as VS Code's Copy Line Down does; pressing it again copies the copy. Ctrl+/ (Cmd+/ on macOS) comments the caret's line, or every line the selection
touches, out with With nothing selected, Ctrl+X and Ctrl+C (Cmd on macOS) cut or copy the caret's whole line, line break included, as VS Code does. Pasting that line with nothing selected puts it above the caret's line rather than in the middle of it, so Ctrl+X, a move, and Ctrl+V moves a line. With a selection they cut and copy the selection as usual. Right-clicking the SQL editor opens a menu with Prettify SQL, Expand SELECT * and Run SQL alongside Cut, Copy, Paste, and Select All. Each entry shows its keyboard shortcut, which remains available if your platform refuses clipboard access to the viewer. The selection is captured when the menu opens, so Ctrl/Cmd+C still copies that selection even if opening the menu moved the caret. Ctrl+wheel (Cmd+wheel on macOS) over the SQL editor zooms its text, a pixel
per notch, between 6 and 48 pixels; a trackpad pinch works too. The line
numbers and suggestions zoom with it. The size lasts until the panel closes,
and a new panel starts at VS Code's The History panel records each command, status, duration, and displayed row count until the document closes. The history export button (Export SQL history ▾) asks which entries to include, successful ones picked by default, then writes one of three files:
All three record when they were exported, in local time with its UTC offset,
such as Running a SQL script as a notebookThe scroll button beside the SQL history buttons in the toolbar (or PK
DuckDB: Open SQL Script as Notebook…) opens a
Run a cell with Ctrl/Cmd+Enter or Shift+Enter, or use Run All, which stops at the first cell that fails. Each cell shows its result under it, up to 1,000 rows. A cell holding several statements runs them in order and shows the last one's result. Cells run exactly as the SQL editor runs them: read-only unless you allow changes, under the same timeout, and recorded in the same history. The notebook's kernel is the file it runs against. It is named after that file and stays with the notebook when you switch viewers. To run the script against another open file, pick that file's kernel. Save writes the script back in its own format, line endings, and byte order mark, so an unedited script saves unchanged. Save also writes each cell's last result under it, as a Jupyter notebook
keeps its outputs: the first 20 rows as a table with the row count, or the
error. In Markdown the table renders in any preview; in a Both notebook types are optional editors: ExportWith one or more column headers selected, Export selected ▾ offers CSV, TSV, PSV, and a typed JSON array. These quick exports contain every row in the current sort order and only the selected columns. Delimited formats include a header and UTF-8 BOM; JSON remains typed and has no BOM. The quick menu requires non-empty, unique column names. Query-result quick exports rerun the successful SELECT so they are not limited to displayed rows. Export… in the viewer toolbar opens a panel over whatever the grid is showing — the active table, or the active SQL query result. A query result export reruns the query, so the file holds every row rather than the display-limited page. The panel chooses:
Column picks last while you stay on the same table, and reset when you switch to another one. All tabs at onceWith more than one table tab open, the panel shows This tab / All tabs. All tabs writes every table in one go — including files you added to the session — in one of four shapes:
Every column goes out, since the tabs do not share a column list, so the column picker is replaced by the list of tables to be written. JSON and Markdown stay single-tab. The SQL Query Result tab is not included: it is a re-run of your query rather than part of the source. Export it on its own from This tab. The file being viewed can never be the destination, whichever format you pick, changes allowed or not. Each format is also a command, which opens the same panel with that format already chosen: Export Active Table or Query Result as CSV, … as Excel, … as Parquet, and … to DuckDB. CSVWritten as plain UTF-8. Check UTF-8 BOM to lead the file with a byte order mark instead. The mark matters when you intend to double-click the file: without one, Excel
on Windows decodes a CSV with the ANSI code page, which turns Thai, Japanese,
and accented text into mojibake. It is off by default because most other
tools — JSON ArrayWritten as a typed JSON array of row objects. Numbers and booleans remain JSON values rather than being flattened to display text, and the file has no BOM. Markdown tableWritten as a GitHub-flavoured Markdown table. Pipes, backslashes, and line
breaks in values are escaped so they cannot change the table shape. Every
numeric, ParquetA single ExcelWritten as a single-sheet Excel stores no column types, so this is the format to pick when the numbers matter more than the types. It also caps a sheet at 1,048,576 rows; a larger export reports that rather than truncating. DuckDBWritten into a DuckDB database as a table you name. Column types survive, so a
Choosing a database that already exists adds the table to it and keeps the tables already there, which is how several exports collect into one file. Your operating system's save dialog still asks whether to replace the file; the export never does. The one case that overwrites is a name already used inside that database, and it asks first. Excel is the one source whose types need help here. The format has no integer
type — every numeric cell is a floating-point number — so a column of whole
numbers would otherwise be stored as Adding files to a viewerAny open viewer (DuckDB, Parquet, CSV, or Excel) can take more files as new tabs, so you can join a CSV against a database table without leaving it:
Each file becomes a table named after it, and each readable sheet of a
workbook becomes its own table (
If a name is already taken, the new table gets a suffix ( Double-click an added tab to rename its table — or press F2 with the tab
focused. Enter commits, Escape puts it back. The name is what SQL calls the
table, so Added tables last for the session only. The rows are copied in when you add the file, and adding one never writes to the file you opened. With changes allowed, SQL can change an added table too, but not for long: every change reloads the viewer, which reads the added files again. They come back if the source is reloaded, and they go away when you close the viewer or a tab's ×. To keep one, export it from its tab with Export… → DuckDB. Dragging files in from the operating system's file manager does not work, because a webview is not given the path. Drag them from the VS Code Explorer instead, or use Add files…. Descriptive statisticsRight-click a tab → Descriptive Statistics to open a table of its columns
in an editor beside the viewer: one row per column, with its type, count,
nulls, null %, approximate distinct count, min, and max, and for a numeric
column the mean, standard deviation, quartiles, median, skewness, and excess
kurtosis — the figures A table tab is described under its own column filters. The Query Result tab is
described by running its SQL again, so the figures cover every row, not just
the rows the grid loaded; only a Opening a tab in its own windowTo see two tables side by side, or to put one on another monitor, pull its tab off the strip: drag it up or down, clear of the tab strip, and let go. A chip under the pointer says Release to open in a new window once it will open. Dragging along the strip, or pressing Escape, leaves the tab where it is. The Query Result tab comes off the same way, with the rows it already has. You can also right-click a tab → Open in New Window, or run PK DuckDB: Open Current Tab in New Window from the Command Palette. The new window is a complete second viewer on the same file, opened on that tab. It has its own grid, profile, chart, and SQL editor, and it shares the first viewer's session: the same SQL history, and the same added tables. Adding, renaming, or closing an added tab in either window changes it in both. The tab stays in the window it came from too, because tearing it off opens a second view of the file, not a move. VS Code for the Web has no separate windows, so there the new viewer opens beside the current one. Tabular source loadingThe viewer uses a scan-then-materialize strategy:
The cache lives in the operating system temporary directory and is removed when the viewer worker closes. Excel sheets are registered immediately and materialized individually when first browsed, profiled, or exported. SQL can query any registered sheet before materialization. Trailing delimitersSeveral systems write a delimited file with the delimiter at the end of every
line, header included — The viewer drops that column, so the grid, the profile, and every export show
the file as it was meant. It is dropped only when both signs agree: the header
cell was blank, and the column holds no value in any row. A column the file
named is always kept, and so is an unnamed one that turns out to carry data —
this can hide a column, but never loses a value. Setting Header to Use Source settings in the viewer toolbar to change storage, delimiter,
header, encoding, type inference, malformed-row handling, or Excel empty-row
behavior for the current open session. Workspace defaults are available under
Commands
Open with DuckDB Sidekick is an Explorer right-click entry rather than a palette command, because it acts on the file you clicked. ContributingBuilding the extension from source, running tests, and packaging a release are covered in DEV.md. LicenseMIT |