Definition
- Catalog – The metadata store holding databases, tables, views, and functions in a three-level namespace: catalog.database.object.
- GenericInMemoryCatalog – The default catalog that keeps definitions in session memory, lost on restart.
- HiveCatalog – Persists metadata in a Hive Metastore backed by a relational database, making definitions durable and shared.
- JdbcCatalog – Connects to a relational database and exposes its real tables as Flink tables automatically.
- Governance – Persistent catalogs enable access control, lineage tracking, and cross-team table sharing.
When the National Bank of India writes SQL against its transaction streams, every table needs a definition. The default in-memory catalog is like writing those definitions on a whiteboard: the moment the room is cleared, they are gone. A HiveCatalog is like storing them in a shared central register that every department can read, so the accounts table defined by the payments team is instantly usable by the fraud team and survives overnight reboots.
Understanding the Concepts
What is a Flink SQL catalog?
Flink SQL organizes metadata in a three-level namespace: catalog, then database, then object (table, view, or function). When you write SELECT * FROM accounts, Flink resolves it against the current catalog and database.
-- Fully qualified reference
SELECT * FROM hive_catalog.nbi_db.accounts;
-- Switch to a catalog and database
USE CATALOG hive_catalog;
USE nbi_db;
SELECT * FROM accounts; -- resolves to hive_catalog.nbi_db.accounts
What is the GenericInMemoryCatalog?
The default catalog keeps every CREATE TABLE in the heap of the current TableEnvironment. When the SQL client exits or the job restarts, all definitions are lost.
package com.bank.flink;
import org.apache.flink.table.api.EnvironmentSettings;
import org.apache.flink.table.api.TableEnvironment;
public class InMemoryCatalogDemo {
public static void main(String[] args) {
TableEnvironment tEnv = TableEnvironment.create(
EnvironmentSettings.inStreamingMode());
// This table exists only in memory
tEnv.executeSql(
"CREATE TABLE transactions (" +
" txn_id STRING, amount DECIMAL(15,2)" +
") WITH ('connector'='kafka', 'topic'='nbi-txns', 'format'='json'," +
" 'properties.bootstrap.servers'='kafka.bank.internal:9092')"
);
// When this process exits, the table definition is gone.
// Next time, you must re-run the CREATE TABLE.
}
}
What is HiveCatalog?
HiveCatalog stores metadata in a Hive Metastore backed by a relational database like MySQL. Definitions are durable and shared across all sessions that connect to the same metastore.
-- Register a HiveCatalog
CREATE CATALOG hive_catalog WITH (
'type' = 'hive',
'hive-conf-dir' = '/opt/hive-conf'
);
USE CATALOG hive_catalog;
CREATE DATABASE IF NOT EXISTS nbi_db;
USE nbi_db;
-- This table definition is now stored in the Hive Metastore.
-- It survives cluster restarts and is visible to all jobs.
CREATE TABLE transactions (
txn_id STRING,
account_id STRING,
amount DECIMAL(15, 2),
event_time TIMESTAMP(3),
WATERMARK FOR event_time AS event_time - INTERVAL '5' SECOND
) WITH (
'connector' = 'kafka',
'topic' = 'nbi-transactions',
'format' = 'json',
'properties.bootstrap.servers' = 'kafka.bank.internal:9092'
);
package com.bank.flink;
import org.apache.flink.table.api.EnvironmentSettings;
import org.apache.flink.table.api.TableEnvironment;
public class HiveCatalogDemo {
public static void main(String[] args) {
TableEnvironment tEnv = TableEnvironment.create(
EnvironmentSettings.inStreamingMode());
// Register HiveCatalog programmatically
tEnv.executeSql(
"CREATE CATALOG hive_catalog WITH (" +
" 'type' = 'hive'," +
" 'hive-conf-dir' = '/opt/hive-conf'" +
")"
);
tEnv.executeSql("USE CATALOG hive_catalog");
// Now tables persist in the Hive Metastore
}
}
What is JdbcCatalog?
JdbcCatalog connects to a live relational database and exposes its real tables as Flink tables automatically. You do not write any CREATE TABLE for those tables.
CREATE CATALOG pg_catalog WITH (
'type' = 'jdbc',
'base-url' = 'jdbc:postgresql://db.bank.internal:5432/',
'default-database' = 'nbi',
'username' = '${JDBC_USER}',
'password' = '${JDBC_PASS}'
);
USE CATALOG pg_catalog;
-- The PostgreSQL accounts table is automatically available
SELECT account_id, balance FROM nbi.accounts WHERE status = 'ACTIVE';
-- No CREATE TABLE needed: the catalog discovers it from the database
How do you compare the three catalogs?
| Feature | InMemory | HiveCatalog | JdbcCatalog |
|---|---|---|---|
| Persistence | None (lost on restart) | Hive Metastore (durable) | Live database (always current) |
| Sharing | Single session | All sessions via metastore | All sessions via catalog |
| DDL needed | Yes, every time | Yes, once | No (auto-discovered) |
| Custom connectors | Yes | Yes | No (JDBC only) |
| Best for | Experiments | Production shared tables | Querying existing databases |
Why are catalogs important for production?
Catalogs separate the where-is-the-data concern from the query logic. This is central to governance.
Without persistent catalog: Job A starts → runs CREATE TABLE transactions (...) Job B starts → runs CREATE TABLE transactions (...) ← different options! Job A restarts → must re-run DDL or it fails Problem: definitions drift, manual re-entry, no single source of truth With HiveCatalog: Data engineer creates transactions table once in the metastore. Job A, Job B, Job C all read the same definition. Cluster restarts → definitions survive. Single source of truth for connector options, watermarks, formats.
// Production pattern: register catalog at session start
TableEnvironment tEnv = TableEnvironment.create(
EnvironmentSettings.inStreamingMode());
tEnv.executeSql("CREATE CATALOG hive_catalog WITH ('type'='hive', ...)");
tEnv.executeSql("USE CATALOG hive_catalog");
tEnv.executeSql("USE nbi_db");
// All tables are now available from the persistent catalog
What about views and functions in catalogs?
Catalogs also store views and user-defined functions, so reusable business logic is defined once and shared.
-- Reusable view stored in the catalog
CREATE VIEW active_accounts AS
SELECT * FROM accounts WHERE status = 'ACTIVE';
-- Reusable function stored in the catalog
CREATE FUNCTION currency_convert AS 'com.bank.udf.CurrencyConvertFunction';
-- Any team can use these without redeclaring
SELECT account_id, currency_convert(balance, 'USD', 'INR') FROM active_accounts;
What should a senior engineer know?
- In production, never rely on the in-memory catalog for shared tables. Use HiveCatalog or an enterprise catalog.
- Modern deployments use Iceberg or Paimon catalogs for full table-format integration with lakehouse semantics.
- Access control and lineage tracking depend on persistent catalog metadata.
- Register catalogs in the Flink SQL gateway or session initialization script so they are always available.
- Multiple catalogs can be registered in one session for cross-catalog queries.
-- Cross-catalog query: join Kafka stream with PostgreSQL lookup
SELECT t.txn_id, t.amount, a.holder_name
FROM hive_catalog.nbi_db.transactions t
JOIN pg_catalog.nbi.accounts a
ON t.account_id = a.account_id;
Visual Overview
Flink SQL Catalog Hierarchy ┌─────────────────────────────────────────┐ │ Flink Session │ │ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ default_catalog│ │ hive_catalog │ │ │ │ (in-memory) │ │ (persistent) │ │ │ │ │ │ │ │ │ │ ┌───────────┐ │ │ ┌───────────┐ │ │ │ │ │default_db │ │ │ │ nbi_db │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ temp_table│ │ │ │transactions│ │ │ │ │ │ (lost on │ │ │ │ accounts │ │ │ │ │ │ restart) │ │ │ │ (durable) │ │ │ │ │ └───────────┘ │ │ └───────────┘ │ │ │ └──────────────┘ └──────────────┘ │ └─────────────────────────────────────────┘
InMemory vs HiveCatalog Lifecycle
InMemory: HiveCatalog:
┌──────────┐ ┌──────────┐
│ Session │ │ Session │
│ starts │ │ starts │
│ CREATE TBL│ │ CREATE TBL│──▶ Hive Metastore
│ (in heap) │ │ (stored) │ (MySQL backend)
└─────┬────┘ └─────┬────┘
│ restart │ restart
▼ ▼
┌──────────┐ ┌──────────┐
│ Session │ │ Session │
│ starts │ │ starts │
│ TABLE GONE│ │ TABLE │◀── Hive Metastore
│ must redo │ │ STILL HERE│ (still has it)
└──────────┘ └──────────┘
Key Takeaway
A Flink SQL catalog stores the definitions of databases, tables, views, and functions in a three-level namespace. The default GenericInMemoryCatalog keeps everything in the session's heap, so definitions vanish on restart. HiveCatalog persists metadata in a Hive Metastore backed by a relational database, making definitions durable and shared across all sessions. JdbcCatalog connects to a live database and automatically exposes its tables without any DDL.
Catalogs matter for production because they are the backbone of metadata governance. Without a persistent catalog, every job must re-run DDL after a restart, definitions drift between teams, and there is no single source of truth. With HiveCatalog, one team defines the transactions table once and every other team queries it immediately.
At the National Bank of India, payments, fraud, and reporting teams all needed the same core tables. Early on, each team redefined them in their own in-memory session, so definitions drifted and every restart wiped them out. We moved to HiveCatalog backed by a shared metastore, and definitions survived every restart while all teams shared a single source of truth.
Remember one sentence: use a persistent catalog like HiveCatalog so table definitions survive restarts and are shared across teams, because the in-memory catalog loses everything when the session exits.
---