Launching PuppyGraph from Snowflake Marketplace
PuppyGraph is available on the Snowflake Marketplace as a Native App running on Snowpark Container Services: the engine runs entirely inside your Snowflake account, reads the tables you grant it directly — no ETL, no credentials to configure — and serves its UI through a Snowflake-authenticated URL.
1. Install and activate
- Find PuppyGraph on the Snowflake Marketplace and click Get.
- Click Grant to approve the requested account privileges (compute pool, warehouse, service endpoint), then Activate. The app creates a dedicated compute pool and a small warehouse, then starts the engine — the first start takes a few minutes.
- Click Launch App. While the engine starts you see a "PuppyGraph is starting up" page that clears automatically — no refresh needed.
2. Give PuppyGraph access to your data
Follow along with this demo dataset (run in a worksheet, replacing
<app_name> with your installed application name — the in-app instructions
show it pre-filled):
CREATE DATABASE IF NOT EXISTS GRAPH_DEMO;
CREATE SCHEMA IF NOT EXISTS GRAPH_DEMO.SOCIAL;
CREATE OR REPLACE TABLE GRAPH_DEMO.SOCIAL.PERSON (ID INT, NAME STRING, AGE INT);
CREATE OR REPLACE TABLE GRAPH_DEMO.SOCIAL.KNOWS (SRC INT, DST INT);
INSERT INTO GRAPH_DEMO.SOCIAL.PERSON VALUES (1,'marko',29),(2,'vadas',27),(3,'josh',32),(4,'peter',35);
INSERT INTO GRAPH_DEMO.SOCIAL.KNOWS VALUES (1,2),(1,3);
GRANT USAGE ON DATABASE GRAPH_DEMO TO APPLICATION <app_name>;
GRANT USAGE ON ALL SCHEMAS IN DATABASE GRAPH_DEMO TO APPLICATION <app_name>;
GRANT SELECT ON ALL TABLES IN DATABASE GRAPH_DEMO TO APPLICATION <app_name>;
Until data is granted, the app shows the first-run panel below with a live "Watching for access…" indicator — once you run the grants, it advances to the schema builder by itself within about a minute. That is your confirmation the grant worked.

First-run panel before any data is granted
Iceberg tables
GRANT SELECT ON ALL TABLES does not cover Snowflake Iceberg tables —
they are a separate object class. Add
GRANT SELECT ON ALL ICEBERG TABLES IN DATABASE <db> TO APPLICATION <app_name>;
or grant a database role. Tables shared through the Snowsight table picker
(instead of SQL grants) appear under the puppy_snowflake_tables catalog in
its graph_sources schema.
Each granted database appears in the left catalog panel as a catalog named
after it in lowercase — for the demo, expand graph_demo → SOCIAL to see
PERSON and KNOWS. If a schema shows "No tables found", the table-level
grant is missing.
3. Map tables to nodes and edges
Tables whose rows are entities become nodes; tables that connect two entities become edges.
- Click Add Node in the toolbar. In the Select Table for Node dialog,
expand
graph_demothenSOCIAL, pickPERSON, and click Next. In the Add Node wizard, click Add to ID and pickIDto make it the node identifier;NAMEandAGEremain under Attribute Columns — set their aliases to lowercasenameandage(property lookup is case-sensitive, and unquoted Snowflake columns are uppercase). Set the Node Label topersonand submit. - Click Add Edge in the toolbar and pick
KNOWSthe same way. In the Add Edge wizard, turn Enable ID off (the table has no edge-ID column), set the label toknows, choosepersonas the From node usingSRCandpersonas the To node usingDST, then click Next and Add Edge.
The schema canvas now shows person —knows→ person. Changes apply
immediately — no re-upload or restart.

The schema canvas after mapping tables to nodes and edges
4. Run your first query
Open Query in the left navigation and execute:
Expected result with the demo data — two rows: marko | vadas and
marko | josh. The graph view renders the same result visually.

The expected result: Success, 2 rows
You can also query from any worksheet or Snowpark session:
SELECT <app_name>.api.cypher(
'MATCH (a:person)-[:knows]->(b:person) RETURN a.name AS who, b.name AS knows');
This returns the records as a VARIANT array ({"Keys": [...], "Values": [...]}
per row) — use LATERAL FLATTEN to project columns.
Cost controls and troubleshooting
- Suspend the engine and its compute pool when idle:
CALL <app_name>.config.suspend_engine();— state is preserved; resume withCALL <app_name>.config.resume_engine();(about 2 minutes). - "Watching for access…" never advances: the grant likely targeted a different application name — use the exact name shown in the in-app instructions.
- Query returns "no healthy leader": the engine is still starting or was suspended; wait for the startup page to clear or resume the engine.