PostgreSQL LIKE Operator

Learn how to use the PostgreSQL LIKE operator for pattern matching with % and _ wildcards, ILIKE for case-insensitive search, and performance tips for indexed pattern queries.

6 min read · PostgreSQL 9.0+ · Back to overview

Quick Answer

The LIKE operator matches a string against a pattern using two wildcards: % matches any sequence of zero or more characters, and _ matches exactly one character. LIKE is case-sensitive. Use ILIKE (a PostgreSQL extension) for case-insensitive matching.

Spin up a Postgres database in 20 seconds with Vela.

Try Vela Sandbox

The LIKE operator in PostgreSQL matches a string value against a pattern. It is the standard way to perform wildcard-based string searches in WHERE clauses and is case-sensitive by default. PostgreSQL also provides ILIKE for case-insensitive matching.

Syntax

-- Match pattern
value LIKE pattern

-- Case-insensitive (PostgreSQL extension)
value ILIKE pattern

-- Negation
value NOT LIKE pattern
value NOT ILIKE pattern

PostgreSQL also supports symbolic shorthand:

SymbolEquivalent
~~LIKE
~~*ILIKE
!~~NOT LIKE
!~~*NOT ILIKE

If the pattern contains no wildcard characters, LIKE behaves identically to the = operator.

Pattern Wildcards

WildcardMatches
%Any sequence of zero or more characters
_Exactly one character

Practical Example

Create a sample product catalog for testing pattern searches:

CREATE TABLE products (
  product_id  SERIAL PRIMARY KEY,
  sku         VARCHAR(20)  NOT NULL UNIQUE,
  name        VARCHAR(150) NOT NULL,
  category    VARCHAR(60)  NOT NULL,
  description TEXT
);

INSERT INTO products (sku, name, category, description) VALUES
  ('EL-001', 'Wireless Bluetooth Headset',  'Electronics', 'Over-ear, noise cancelling'),
  ('EL-002', 'USB-C Charging Hub',           'Electronics', '7-port hub, 100W PD'),
  ('EL-003', 'Portable Bluetooth Speaker',   'Electronics', 'Waterproof, 20h battery'),
  ('FN-001', 'Ergonomic Office Chair',       'Furniture',   'Lumbar support, adjustable'),
  ('FN-002', 'Height-Adjustable Desk',       'Furniture',   'Electric, 3-preset memory'),
  ('AC-001', 'Laptop Cooling Stand',         'Accessories', 'Aluminium, 2 USB ports'),
  ('AC-002', 'Cable Management Kit',         'Accessories', 'Velcro straps and clips');

Find all electronics products:

SELECT sku, name
FROM products
WHERE category LIKE 'Electr%';

Find products with “Bluetooth” anywhere in the name (case-sensitive):

SELECT sku, name
FROM products
WHERE name LIKE '%Bluetooth%';

Expected result:

  sku   |            name
--------+-----------------------------
 EL-001 | Wireless Bluetooth Headset
 EL-003 | Portable Bluetooth Speaker

Find products with “bluetooth” (any case) using ILIKE:

SELECT sku, name
FROM products
WHERE name ILIKE '%bluetooth%';
-- Returns the same 2 rows, regardless of case in the stored data

Use the _ wildcard to match SKUs with a specific format (2 letters, dash, 3 digits):

SELECT sku, name
FROM products
WHERE sku LIKE '__-___';

This returns all rows because all SKUs follow that pattern.

ILIKE and Case-Insensitive Searching

-- Only matches 'Ergonomic Office Chair' — exact case
SELECT name FROM products WHERE name LIKE 'ergonomic%';  -- 0 rows

-- Matches regardless of case
SELECT name FROM products WHERE name ILIKE 'ergonomic%';
-- Returns: Ergonomic Office Chair

ESCAPE for Literal Wildcards

If your data contains literal % or _ characters, use the ESCAPE clause:

-- Find descriptions containing a literal percent sign, e.g. "20% off"
SELECT sku, description
FROM products
WHERE description LIKE '%20!%%' ESCAPE '!';

The !% sequence is treated as a literal % rather than a wildcard.

Performance Notes

Pattern typeIndex usageRecommendation
LIKE 'prefix%'B-tree index ✓Standard B-tree index is sufficient
LIKE '%suffix'Sequential scanUse pg_trgm GIN index
LIKE '%substring%'Sequential scanUse pg_trgm GIN index
ILIKE 'prefix%'Only with citext or functional indexUse lower() index or citext column

Create a trigram index to support substring searches:

CREATE EXTENSION IF NOT EXISTS pg_trgm;

CREATE INDEX idx_products_name_trgm
ON products
USING GIN (name gin_trgm_ops);

After creating the index, verify it is used:

EXPLAIN ANALYZE
SELECT sku, name FROM products WHERE name ILIKE '%bluetooth%';

Testing with Vela

Schema changes like adding a trigram index for LIKE performance improvements are exactly the kind of migration to validate before applying to production. Use Vela’s database branching to create a production-data branch, add the GIN index, and benchmark LIKE '%term%' queries with EXPLAIN ANALYZE to confirm the index is used and query times improve — all without touching the live database.

Production Tips

  • LIKE 'prefix%' (trailing wildcard only) can use a standard B-tree index. This is the most efficient pattern form.
  • LIKE '%anything' or LIKE '%anything%' forces a sequential scan without a trigram index. Use pg_trgm GIN indexes for substring searches on large tables.
  • Standard B-tree indexes are case-sensitive and do not support ILIKE. Use a citext column, a lower(column) functional index, or a pg_trgm GIN index with gin_trgm_ops for case-insensitive indexed searches.
  • For language-aware full-text search (stemming, ranking), use PostgreSQL’s native tsvector/tsquery instead of LIKE.
  • Avoid using LIKE on very high-cardinality columns without an index — it will result in a full sequential scan on large tables.
  • Use EXPLAIN ANALYZE to confirm whether the query planner uses your index or reverts to a sequential scan.

Continue in Filtering Data: IS NULL.

Related in this section: PostgreSQL WHERE · AND Operator · OR Operator

Frequently Asked Questions

What is the difference between LIKE and ILIKE in PostgreSQL?
LIKE performs case-sensitive pattern matching — LIKE 'Pro%' only matches strings beginning with uppercase P-r-o. ILIKE is a PostgreSQL extension that is case-insensitive — ILIKE 'pro%' matches 'Product', 'PRODUCT', 'product', and so on. ILIKE is not part of the SQL standard but is widely used in PostgreSQL applications.
Does LIKE lock the table?
No. LIKE is a predicate operator evaluated at query time. It acquires no locks beyond the standard shared read lock used by any SELECT. For UPDATE or DELETE statements, the same locks apply as without LIKE.
What happens to dependent indexes when I use a leading wildcard with LIKE?
A B-tree index on the column cannot be used for leading-wildcard patterns like LIKE '%term%' or LIKE '%term'. The planner falls back to a sequential scan. To support substring searches efficiently, install the pg_trgm extension and create a GIN trigram index on the column.
Can I use LIKE with an ESCAPE character?
Yes. Use the ESCAPE clause to designate a character that treats the next wildcard character as a literal: WHERE code LIKE '15$%off' ESCAPE '$' matches the literal string '15%off'. You can choose any character not present in the data as the escape character.
What is the safest way to use LIKE for full-text search in production?
For prefix searches (LIKE 'term%'), a standard B-tree index is sufficient. For substring searches (LIKE '%term%'), install pg_trgm and create a GIN index with gin_trgm_ops. For language-aware full-text search, use PostgreSQL's built-in tsvector/tsquery system. Validate index usage with EXPLAIN ANALYZE before deploying.