docs/content/stable/faq/compatibility.md
YugabyteDB supports two flavors of distributed SQL.
{{<lead link="/stable/api/">}} API {{</lead>}}
YSQL is a fully-relational SQL API that is wire compatible with the SQL language in PostgreSQL. It is best fit for RDBMS workloads that need horizontal write scalability and global data distribution while also using relational modeling features such as JOINs, distributed transactions and referential integrity (such as foreign keys).
{{<lead link="../../explore/">}} Explore YSQL features {{</lead>}}
YCQL is a semi-relational SQL API that is best fit for internet-scale OLTP and HTAP applications needing massive data ingestion and blazing-fast queries. It supports distributed transactions, strongly consistent secondary indexes and a native JSON column type. YCQL has its roots in the Cassandra Query Language.
{{<lead link="../../explore/">}} Explore YCQL features {{</lead>}}
{{< note title="Note" >}}
The YugabyteDB APIs are isolated and independent from one another today. This means that the data inserted or managed by one API cannot be queried by the other API. Additionally, there is no common way to access the data across the APIs (external frameworks such as Presto can help for basic cases).
The net impact is that you need to select an API first before undertaking detailed database schema/query design and implementation.
{{< /note >}}
You should pick YCQL over YSQL if your application:
If you have a specific use case in mind, share it in our Slack community and the community can help you decide the best approach.
The YSQL shell (ysqlsh) is functionally similar to PostgreSQL's psql , but uses different default values for some variables (for example, the default user, default database, and the path to TLS certificates). This is done for the user's convenience. In the Yugabyte bin directory, the deprecated psql alias opens the ysqlsh CLI.
{{<lead link="../../api/ysqlsh/">}} Explore ysqlsh {{</lead>}}
<!-- ### What is the status of the YEDIS API? In the near-term, Yugabyte is not actively working on new feature or driver enhancements to the [YEDIS](../../yedis/) API other than bug fixes and stability improvements. Current focus is on [YSQL](../../api/ysql/) and [YCQL](../../api/ycql/). For key-value workloads that need persistence, elasticity and fault-tolerance, YCQL (with the notion of keyspaces, tables, role-based access control, and more) is often a great fit, especially if the application is new rather than an existing one already written in Redis. The YCQL drivers are also more clustering aware, and hence YCQL is expected to perform better than YEDIS for equivalent scenarios. In general, our new feature development (support for data types, built-ins, TLS, backups, and more), correctness testing (using Jepsen), and performance optimization is in the YSQL and YCQL areas. -->API compatibility refers to the fact that the database APIs offered by YugabyteDB servers implement the same wire protocol and modeling/query language as that of an existing database. Because client drivers, command line shells, and IDE and other ecosystem integrations of the existing database rely on this wire protocol and modeling/query language, they are expected to work with YugabyteDB without major modifications.
{{< note title="Note" >}} The YSQL API is compatible with PostgreSQL. This means PostgreSQL client drivers, psql command line shell, IDE integrations such as TablePlus and DBeaver, and more can be used with YugabyteDB. The same concept applies to YCQL in the context of the Apache Cassandra Query Language. {{< /note >}}
YugabyteDB's API compatibility is aimed at accelerating developer onboarding. By integrating well with the existing ecosystem, YugabyteDB ensures that developers can get started quickly using a language they are already comfortable with.
YugabyteDB's API compatibility is not aimed at lift-and-shift porting of existing applications written for the original language. This is because existing applications are not written to take advantage of the distributed, strongly-consistent storage architecture that YugabyteDB provides. For such existing applications, you should modify your previously monolithic PostgreSQL and/or non-transactional Cassandra data access logic as you migrate to YugabyteDB.
As highlighted in Distributed PostgreSQL on a Google Spanner Architecture – Query Layer, YSQL reuses the open source PostgreSQL query layer (written in C) as much as possible and as a result is wire-compatible with PostgreSQL dialect and client drivers. Specifically, YSQL in v2025.1 and later is based on PostgreSQL version 15, while earlier versions are based on PostgreSQL version 11.2. Following are some of the currently supported features:
{{<lead link="../../explore/ysql-language-features/">}} Explore SQL features {{</lead>}}
YugabyteDB's goal is to remain as compatible with PostgreSQL as much as possible. If you see a feature currently missing, you can file a GitHub issue.
The YugabyteDB APIs are currently isolated and independent from one another. Data inserted or managed by one API cannot be queried by the other API. Additionally, Yugabyte does not provide a way to access the data across the APIs. An external framework, such as Presto, might be helpful for basic use cases. For an example that joins YCQL and YSQL data, see the blog post about Presto on YugabyteDB: Interactive OLAP SQL Queries Made Easy.
Allowing YCQL tables to be accessed from the PostgreSQL-compatible YSQL API as foreign tables using foreign data wrappers (FDW) is on the roadmap. You can comment or increase the priority of the associated GitHub issue.
YCQL is compatible with v3.4 of Apache Cassandra QL (CQL). Following questions highlight how YCQL differs from CQL.
{{<lead link="https://www.yugabyte.com/blog/apache-cassandra-lightweight-transactions-secondary-indexes-tunable-consistency/">}} The Truth Behind Tunable Consistency, Lightweight Transactions, and Secondary Indexes {{</lead>}}
By default, inserts overwrite data on primary key collisions. So INSERTs do an upsert. This an intended CQL feature. In order to insert data only if the primary key is not already present, add a clause "IF NOT EXISTS" to the INSERT statement. This will cause the INSERT fail if the row exists.
Following is an example from CQL:
INSERT INTO mycompany.users (id, lastname, firstname)
VALUES (100, 'Smith', 'John')
IF NOT EXISTS;
Yes, you can have collection data types as primary keys as long as they are marked FROZEN. Collection types that are marked FROZEN do not support partial matches.
COUNTER data type and INTEGER data type?Unlike Apache Cassandra, YugabyteDB COUNTER type is almost the same as INTEGER types. There is no need of lightweight transactions requiring 4 round trips to perform increments in YugabyteDB - these are efficiently performed with just one round trip.
In Apache Cassandra, the highest timestamp provided always wins. For example:
INSERT with timestamp far in the future:
> INSERT INTO table (c1, c2, c3) VALUES (1, 2, 3) USING TIMESTAMP 1607681258727447;
> SELECT * FROM table;
c1 | c2 | c3
----+----+----
1 | 2 | 3
INSERT at the current timestamp does not overwrite previous value which was written at a higher timestamp:
> INSERT INTO table (c1, c2, c3) VALUES (1, 2, 4);
> SELECT * FROM table;
c1 | c2 | c3
----+----+----
1 | 2 | 3
On the other hand in Yugabyte, for efficiency purposes INSERTs and UPDATEs without the USING TIMESTAMP clause always overwrite the older values. On the other hand, if you have the USING TIMESTAMP clause, then appropriate timestamp ordering is performed. Example:
> INSERT INTO table (c1, c2, c3) VALUES (1, 2, 3) USING TIMESTAMP 1000;
> SELECT * FROM table;
c1 | c2 | c3
----+----+----
1 | 2 | 3
INSERT with timestamp far in the future, this would overwrite old value.
> INSERT INTO table (c1, c2, c3) VALUES (1, 2, 4) USING TIMESTAMP 1607681258727447;
> SELECT * FROM table;
c1 | c2 | c3
----+----+----
1 | 2 | 4
INSERT without 'USING TIMESTAMP' will always overwrite.
> INSERT INTO table (c1, c2, c3) VALUES (1, 2, 5);
> SELECT * FROM table;
c1 | c2 | c3
----+----+----
1 | 2 | 5