Skip to main content

Read-Only Database Access and Safety

The desktop reads the live schema, but it cannot write.

Updated 4 min readMarkdown

Quick answer: The desktop connects to the database through saved profiles whose passwords are never returned, and it runs a read-only SELECT with a bounded row set through database.runSelect. Writes and DDL are blocked, so the software can read the live tables and keys for reconciliation but cannot modify the storage.

Why access is read-only

Reconciliation needs a real baseline, and that means reading the live tables and enforced keys rather than a guessed schema. It does not require writing, and giving a modeling tool write access would add a risk that the feature does not need.

Keeping the connection read-only lets the desktop observe the database while removing the chance that a generated or exploratory change reaches the storage.

The safety controls

Control Behavior
Saved profiles Connections are stored, passwords are never returned
runSelect Runs a read-only SELECT with a bounded row set
Writes Blocked
DDL Blocked
Row set Bounded so a query cannot return an unbounded result

The bounded row set matters because a read-only query that returns no limit can still pull an enormous amount of data, and the cap keeps the observation controlled.

How a read-only connection is used

  1. Save the connection as a profile without exposing the password back.
  2. Read the live tables and the enforced keys in the Observed layer.
  3. Run a bounded SELECT to inspect specific rows when needed.
  4. Compare the observation against the derived model.
  5. Keep every write and DDL blocked and generated for review.

The observed data feeds the reconciliation, and the enforced keys are part of the evidence. None of those steps need a write, so the connection stays narrow.

Consider a team reconciling a billing service. They save the connection once, read the live invoices table and its enforced foreign key, and run a bounded SELECT to inspect a handful of rows where the field looks wrong. The same tool that generates the proposed column cannot write it, so even if a migration contains a mistake, the connection refuses the change, and the team applies the reviewed script through a separate process. The bounded SELECT also keeps the inspection from pulling the full invoices table, which could be millions of rows, and the cap makes the observation predictable. Across the workflow the software reads and generates, and at no point does it hold a path that modifies the storage.

Why credentials are handled carefully

A saved profile stores the connection, but the password is never returned to the interface, which keeps the credential from being read out after it is saved. Treat the profile as a stored connection rather than a place to retrieve the secret, and manage the credential through the same careful channel as the other process-level secrets.

This is the same boundary that keeps generated SQL from being executed. The tool can read and generate, and it cannot write, so a mistake in a generated migration cannot be applied through the connection. The actual change is run separately after a review.

This follows the least-privilege idea. A process that only needs to read should not be given a credential that can write, and limiting the profile at the connection layer means the protection does not depend on a person remembering to avoid a destructive action. The blocked write is a hard boundary rather than a warning, and a DDL statement cannot run through the same profile even if it is pasted in by hand.

Powerduck keeps the read-only limit and the credential handling in the data layer, so observation and modification stay separate.

Frequently asked questions

Can the desktop write to the database? No. Only a read-only SELECT runs, and writes and DDL are blocked.

Why is the row set bounded? To keep a read-only query from returning an unbounded amount of data and to keep the observation controlled.

Are the saved passwords returned? No. The profile stores the connection, but the password is never returned.

The bottom line

The data layer is read-only by design: saved profiles never return passwords, runSelect executes a bounded SELECT, and writes and DDL are blocked. This gives the reconciliation a real baseline while removing any path through which the desktop could modify the storage. Read and generate freely, and keep the actual write in a separate, reviewed step. A connection that cannot write cannot be the source of an accidental change. Read more in the API data model guide.

No comments yet. Be the first to comment.