> ## Documentation Index
> Fetch the complete documentation index at: https://ngquct-feat-2095-query-authoring.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Autocomplete

> Schema-aware SQL autocomplete for keywords, tables, columns, and functions

Autocomplete suggests keywords, tables, columns, and functions based on where your cursor is and what tables are in scope.

<Frame caption="Context-aware autocomplete">
  <img className="block dark:hidden" src="https://mintcdn.com/ngquct-feat-2095-query-authoring/zWRCChdVRm9fZrst/images/autocomplete.png?fit=max&auto=format&n=zWRCChdVRm9fZrst&q=85&s=8a0cc733f8734bb79acc60b0e8914e77" alt="Autocomplete" width="1560" height="960" data-path="images/autocomplete.png" />

  <img className="hidden dark:block" src="https://mintcdn.com/ngquct-feat-2095-query-authoring/zWRCChdVRm9fZrst/images/autocomplete-dark.png?fit=max&auto=format&n=zWRCChdVRm9fZrst&q=85&s=cce5833f18299e4a72d67c7152f0ff67" alt="Autocomplete" width="1560" height="960" data-path="images/autocomplete-dark.png" />
</Frame>

Suggestions appear as you type, from the first character, and after `.` or a space, with a 50ms debounce. There is no minimum prefix. With nothing typed yet, the popup stays hidden in clauses where listing everything is noise (for example after a comma in a SELECT list); it still opens automatically after FROM, JOIN, ON, and other clauses where browsing helps.

| Key              | Action                                             |
| ---------------- | -------------------------------------------------- |
| `Ctrl+Space`     | Open the popup anywhere, even with an empty prefix |
| `Up` `Down`      | Move through suggestions                           |
| `Return` / `Tab` | Accept the selected suggestion                     |
| `Escape`         | Dismiss and keep typing                            |

## Completion Types

### SQL Keywords

```sql theme={null}
SEL|  -- SELECT
FROM users WH|  -- WHERE
SELECT * FROM users WHERE name LIKE '%test%' ORD|  -- ORDER BY
```

### Table Names

Tables appear after FROM, JOIN, INSERT INTO, and similar keywords:

```sql theme={null}
SELECT * FROM |  -- All tables
SELECT * FROM us|  -- Tables starting with "us": users, user_roles
SELECT * FROM a JOIN b ON a.id = b.id JOIN |  -- All tables, even after an ON condition
```

The clause is detected at the cursor, so a second or third JOIN suggests tables even when an ON condition comes before it. In a table position, tables lead the list ahead of keywords.

### Column Names

Columns are suggested in SELECT, WHERE, ORDER BY, GROUP BY, and other column contexts.

If a FROM clause exists anywhere in the statement (even after the cursor), columns come from those tables. If no FROM clause exists yet, columns from all cached tables appear as fallback; ambiguous names are qualified: `users.id`, `orders.id`.

```sql theme={null}
SELECT na|  -- Columns matching "na" from all cached tables
SELECT | FROM users  -- Columns from users
SELECT u.| FROM users u  -- Columns from users via alias
SELECT * FROM users WHERE |  -- Columns from users
```

#### Alias Resolution

Type an alias followed by `.` to see that table's columns:

```sql theme={null}
SELECT
    u.|  -- id, name, email, created_at (from users)
FROM users u
JOIN orders o ON u.id = o.|  -- id, user_id, total (from orders)
```

#### Derived Tables and CTEs

An alias for a subquery (derived table) or a `WITH` table completes the columns that subquery's SELECT list produces, including `AS` renames:

```sql theme={null}
SELECT ahs.|  -- country, avg_score
FROM happiness_scores hs
LEFT JOIN (
    SELECT country, AVG(score) AS avg_score
    FROM happiness_scores
    GROUP BY country
) ahs ON hs.country = ahs.country

WITH totals AS (
    SELECT region, SUM(amount) AS total FROM sales GROUP BY region
)
SELECT t.| FROM totals t  -- region, total
```

Explicit (`AS name`), bare (`country`), and qualified (`t.col`) columns resolve. A `SELECT *` subquery and unaliased expressions like `AVG(score)` have no name to suggest, so they are skipped.

### Functions

SQL functions appear in SELECT, WHERE, and expression contexts:

```sql theme={null}
SELECT |  -- COUNT, SUM, AVG, MAX, MIN, etc.
SELECT COUNT(|  -- Columns and *
WHERE date_column > |  -- NOW(), CURRENT_DATE, etc.
```

Functions from the connection's SQL dialect (e.g. `CONVERT_TIMEZONE` on Snowflake, `SAFE_CAST` on BigQuery) appear alongside the common SQL functions.

### Operators

Operators the connection's dialect declares appear in WHERE, ON, HAVING, and AND contexts, each with what it does and the types it works on.

On PostgreSQL that covers the JSON operators, array and range containment, regex matching, full-text search, and the network operators:

```sql theme={null}
WHERE data -|            -- ->  (field as json), ->>  (field as text)
WHERE payload @|         -- @>  contains, @?  JSON path returns any item
WHERE tags &|            -- &&  arrays overlap
WHERE email ~|           -- ~   POSIX regex, ~* case insensitive
```

The list distinguishes operators that only work on `jsonb` from the ones `json` accepts too, so `@>` is not offered as if it worked on a `json` column.

### Casts

Typing `::` offers the dialect's type names, in the spelling you write rather than the internal catalog name:

```sql theme={null}
SELECT id::|             -- integer, bigint, text, timestamptz, jsonb, uuid, ...
SELECT payload::js|      -- json, jsonb, jsonpath
```

### MongoDB

MongoDB connections use MQL instead of SQL, and the popup follows the shape of the query rather than SQL clauses. What you get depends on exactly where the cursor is:

```js theme={null}
db.|                                  // collections, plus getCollectionNames(), createCollection(), ...
db.users.|                            // find(), aggregate(), updateOne(), insertMany(), ...
db.users.find({ |                     // field names, then $eq, $gt, $in, $exists, $regex, ...
db.users.find({}, { |                 // field names, then $slice, $elemMatch, $meta
db.users.updateOne({}, { |            // $set, $unset, $inc, $push, $addToSet, ...
db.users.updateOne({}, [{ |           // the six stages an update pipeline allows
db.orders.aggregate([{ |              // $match, $group, $lookup, $unwind, $facet, ...
db.orders.aggregate([{ $group: { |    // $sum, $avg, $first, $push, and the expression operators
```

The operator sets are kept apart on purpose. Offering `$match` inside a filter document, or `$gte` where a pipeline stage belongs, is worse than offering nothing. `$set` and `$unset` mean different things as an update operator and as a pipeline stage, and the popup describes whichever one applies at the cursor.

Field names come from a sample of the collection's documents and include nested paths, so a document with `address: { city, zip }` suggests `address`, `address.city` and `address.zip`. Objects inside an array contribute paths too. Shallower fields sort first. Nothing in the query is executed to build the list.

The sample is cached per collection and cleared when you switch database or refresh the connection.

Completion is suppressed inside comments, and braces or brackets inside a string literal do not count as opening a document.

### Favorite Keywords

Favorites you've assigned a keyword to (DB-stored or linked-file `@keyword` frontmatter) appear in the popup as a top-priority match. Type the keyword, accept the suggestion, and the favorite's full SQL replaces the keyword inline. A `;;` in the favorite's SQL sets where the cursor lands after expansion. See [Favorites](/features/favorites#cursor-placement) for how to assign keywords and place the marker.

### Schema Names

For databases with multiple schemas (PostgreSQL):

```sql theme={null}
SELECT * FROM |  -- public, schema1, schema2
SELECT * FROM public.|  -- Tables in public schema
```

Schema-qualified names like `public.users` resolve in FROM, JOIN, UPDATE, INSERT INTO, and CREATE INDEX.

For databases organized as database, schema, table (Snowflake, BigQuery), every segment completes. Tables of schemas you haven't opened in the sidebar are fetched on demand:

```sql theme={null}
SELECT * FROM ANALYTICS_|                      -- databases
SELECT * FROM ANALYTICS_PROD.|                 -- schemas
SELECT * FROM ANALYTICS_PROD.DBT_MARTS.|       -- tables in that schema
SELECT * FROM ANALYTICS_PROD.DBT_MARTS.ORDERS o WHERE o.|  -- columns
```

## Schema Cache

On connection, TablePro fetches table names and loads columns in the background. The column cache holds up to 50 tables with LRU eviction. There is no time-based expiry: cached columns stay until you switch databases or refresh the connection. A failed schema load waits 30 seconds before retrying, to avoid hammering the server.

After external schema changes (migrations, CLI work), press `Cmd+R` (**Query > Refresh**) to reload it. Right-clicking the sidebar's Tables header and choosing **Refresh** does the same.

## Performance

Works on files of any size, including multi-megabyte dumps. For files over 500 KB, only a \~10 KB window around the cursor is analyzed.
