diff --git a/.wordlist.txt b/.wordlist.txt
index 9bf266f7..cc5c5dfb 100644
--- a/.wordlist.txt
+++ b/.wordlist.txt
@@ -10,7 +10,9 @@ Benchmarking
Booleans
booleans
CLI
+Cmd
CMD
+Ctrl
CSC
CSV
CSVs
@@ -25,6 +27,8 @@ DateTime
DELUSER
distro
Ducati
+Dropzone
+Embedder
FOF
FOREACH
Falkor
@@ -35,6 +39,7 @@ FalkorDBGraph
FalkorDBLite
FalkorDBQAChain
Gadepally
+Gemini
Geospatial
GETUSER
GPL
@@ -54,6 +59,8 @@ JS
js
JSDoc
JSON
+JWT
+tokenId
KJDev
Kepner
Keren
@@ -68,6 +75,7 @@ Lipman
LlamaIndex
LocalDateTime
LocalTime
+localStorage
Lovitz
MEM
Miesha
@@ -75,11 +83,14 @@ MotoGP
NRedisGraph
NaN
NFalkorDB
+NEXTAUTH
+NextAuth
NodeJS
Nostem
NumItems
OMP
OpenAI
+OpenAPI
OpenCypher
OpenTelemetry
opentelemetry
@@ -117,6 +128,8 @@ Subcommands
TF
TTY
TypeScript
+UI
+UX
UNIQIE
URIs
UUID
@@ -128,7 +141,6 @@ acos
acyclic
algo
alister
-alister
allShortestPaths
arccosine
arcsine
@@ -175,6 +187,7 @@ falkordblite
fulltext
geospatial
godoc
+gpt
hasLabels
haversin
html
@@ -191,7 +204,6 @@ Jupyter
javadocs
javascript
jedis
-jfalkordb
jinja
jl
jpbourbon
@@ -199,16 +211,20 @@ keyspace
lTrim
labelsList
len
+listGraphs
+list_graphs
lon
malte
matchRegEx
maxCost
maxLen
+memoryUsage
multithreaded
myGraph
myPassword
myUsername
namespace
+nodeId
nan
nav
nd
@@ -252,7 +268,7 @@ redisgraph
relDirection
relTypes
relationshipTypes
-reltype
+relationshipId
reltype
reltypeList
replaceRegEx
@@ -266,6 +282,7 @@ schemas
shortestPath
signum
slowlog
+slowLog
sourceNode
sqrt
stDev
@@ -309,13 +326,13 @@ weightProp
whitespace
xyxel
yaml
+yml
uri
util
vec
euclideanDistance
cosineDistance
vecf
-
Dani
Dovizioso
Pedrosa
@@ -326,10 +343,10 @@ RDB
scalable
scalability
falkorDB
-
GraphName
api
auth
+backend
callbackUrl
csrf
csrfToken
@@ -359,9 +376,7 @@ FalkorConnectionInfo
h1
tokio
async
-falkor
fn
-
xxHash
proc
utf
@@ -372,7 +387,6 @@ thpool
sds
CRoaring
RSALv
-
hostnames
bigmac
calmcode
@@ -381,20 +395,21 @@ kafka
readme
github
pre
-html
-body
table
Explainer
propname
propvalue
ro
GenAI
-
-WCC
-WSL
+Kruskal's
+MSF
+MST
+MSTs
+Prim's
SPpath
SSpath
-
+WCC
+WSL
undirected
preprocessing
subgraphs
@@ -409,7 +424,6 @@ prev
componentId
Betweenness
betweenness
-
LLMs
Groq
ontologies
@@ -431,6 +445,8 @@ cognee
cognify
topoteretes
getzep
+zepai
+Zep's
prune
qdrant
TechCorp
@@ -443,7 +459,6 @@ embeddings
Colab
chatbots
Cognee's
-
alice
cypher
createQuery
@@ -466,7 +481,6 @@ copyGraph
myproject
mut
readOnlyQuery
-
Dunder
Mifflin
scranton
@@ -478,7 +492,6 @@ Munger
queryRelationships
similarityFunction
FIELDTERMINATOR
-backend
md
Opire
hh
@@ -601,7 +614,6 @@ findByAgeNotIn
findByNameAndAgeGreaterThan
findFirstByOrderByCreatedAtDesc
findTop10ByOrderByAgeDesc
-findByAgeGreaterThanEqual
findTop5ByOrderByAgeDesc
findFirstByOrderByAgeAsc
deleteByAge
@@ -639,7 +651,6 @@ OpsRequest
ComponentDefinition
ClusterDefinition
PodMonitor
-BGSAVE
datafile
quorum
NLB
@@ -652,3 +663,92 @@ Addon
addon
LoadBalancer
NodePort
+orphaned
+replicas
+SQL's
+Levenshtein
+autocomplete
+tokenization
+tokenized
+HNSW
+ANN
+tradeoff
+tradeoffs
+unnormalized
+Forst
+configurability
+Metaphone
+ProcedureCall
+
+dimensionality
+efConstruction
+efRuntime
+queryVector
+DESC
+tolist
+pc
+queryEmbedding
+printf
+Jngle
+Homebrew
+libomp
+sdist
+dylib
+xcode
+Trendshift
+
+UDF
+UDFs
+StringUtils
+UpperCaseOdd
+unparseable
+toTimeZone
+jaccard
+Jaccard
+levenshtein
+submap
+Submap
+removeKeys
+removeKey
+fromPairs
+fromJsonList
+fromJsonMap
+toJson
+bitwise
+Bitwise
+Jaro
+PascalCase
+UpperCamelCase
+Winkler
+camelCase
+decapitalize
+indexOf
+indexesOf
+jaroWinkler
+lpad
+regexGroups
+rpad
+snakeCase
+swapCase
+Deduplicate
+Deduplication
+deduplication
+sanitization
+sprintf
+fullMatch
+abc
+upperCamelCase
+shiftLeft
+shiftRight
+
+DBaaS
+GCP
+VPC
+VPCs
+BYOC
+
+memoryInfo
+FDB
+xlarge
+SaaS
+GCP's
diff --git a/README.md b/README.md
index 147897b9..3520354a 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,7 @@
[](https://discord.gg/ErBEqN9E)
[](https://app.falkordb.cloud)
+[](https://trendshift.io/repositories/14787)
# https://docs.falkordb.com
diff --git a/_config.yml b/_config.yml
index a014c6ea..efccb889 100644
--- a/_config.yml
+++ b/_config.yml
@@ -2,6 +2,7 @@ remote_theme: just-the-docs/just-the-docs
title: FalkorDB Docs
description: The FalkorDB documentation
logo: "/images/falkor-logo.png"
+logo_link: "https://www.falkordb.com"
favicon_ico: "/images/favicon.ico"
gtm_tracking: GTM-MBWB627H
diff --git a/_includes/components/sidebar.html b/_includes/components/sidebar.html
new file mode 100644
index 00000000..49c305f8
--- /dev/null
+++ b/_includes/components/sidebar.html
@@ -0,0 +1,36 @@
+{%- comment -%}
+ Include as: {%- include components/sidebar.html -%}
+ Depends on: page(?), site.
+ Results in: HTML for the side bar.
+ Includes:
+ title.html, components/site_nav.html, nav_footer_custom.html
+ Overwrites:
+ nav_footer_custom.
+ Should not be cached, because nav_footer_custom.html might depend on page.
+{%- endcomment -%}
+
+
+
+
+ {% include_cached components/site_nav.html %}
+
+ {% capture nav_footer_custom %}
+ {%- include nav_footer_custom.html -%}
+ {% endcapture %}
+ {% if nav_footer_custom != "" %}
+ {{ nav_footer_custom }}
+ {% else %}
+
+ {% endif %}
+
diff --git a/agentic-memory/graphiti-mcp-server.md b/agentic-memory/graphiti-mcp-server.md
index 8f60d049..804a78c3 100644
--- a/agentic-memory/graphiti-mcp-server.md
+++ b/agentic-memory/graphiti-mcp-server.md
@@ -5,86 +5,113 @@ nav_order: 3
description: "Run Graphiti MCP server with FalkorDB for AI agent memory in Claude Desktop and other MCP clients"
---
-# [EXPERIMENTAL] Graphiti MCP Server
+# Graphiti MCP Server
-{: .warning }
-> **Experimental Feature**: The Graphiti MCP Server integration is experimental and under active development. Features and configurations may change in future releases.
-
-The Graphiti MCP (Model Context Protocol) Server enables AI clients like Claude Desktop and Cursor IDE to interact with FalkorDB-powered knowledge graphs for persistent agent memory. This allows AI assistants to store and retrieve information across conversations, building a rich, contextual memory over time.
+Graphiti is a framework for building and querying temporally-aware knowledge graphs, specifically tailored for AI agents operating in dynamic environments. The Graphiti MCP (Model Context Protocol) Server enables AI clients like Claude Desktop, Cursor IDE, and other MCP-compatible applications to interact with FalkorDB-powered knowledge graphs for persistent agent memory. This allows AI assistants to store and retrieve information across conversations, building a rich, contextual memory over time.
## What is MCP?
The [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) is an open standard that enables AI applications to connect to external data sources and tools. The Graphiti MCP Server implements this protocol to provide AI agents with access to graph-based knowledge storage powered by FalkorDB.
-## Overview
+## Features
+
+The Graphiti MCP Server provides comprehensive knowledge graph capabilities:
-The Graphiti MCP Server provides:
-- **Persistent Memory**: Store conversation history, facts, and relationships in a knowledge graph
-- **Contextual Retrieval**: Query the graph to retrieve relevant information for AI responses
-- **Cross-Session Memory**: Maintain knowledge across multiple conversations and sessions
-- **Multi-Tenant Support**: Isolated memory spaces for different users or agents
-- **Real-Time Updates**: Add new information to the graph as conversations evolve
+- **Episode Management**: Add, retrieve, and delete episodes (text, messages, or JSON data)
+- **Entity Management**: Search and manage entity nodes and relationships in the knowledge graph
+- **Search Capabilities**: Search for facts (edges) and node summaries using semantic and hybrid search
+- **Group Management**: Organize and manage groups of related data with group_id filtering
+- **Graph Maintenance**: Clear the graph and rebuild indices
+- **Multiple LLM Providers**: Support for OpenAI, Anthropic, Gemini, Groq, and Azure OpenAI
+- **Multiple Embedding Providers**: Support for OpenAI, Voyage, Sentence Transformers, and Gemini embeddings
+- **Rich Entity Types**: Built-in entity types including Preferences, Requirements, Procedures, Locations, Events, Organizations, Documents, and more for structured knowledge extraction
+- **HTTP Transport**: Default HTTP transport with MCP endpoint at `/mcp/` for broad client compatibility
+- **Queue-based Processing**: Asynchronous episode processing with configurable concurrency limits
## Prerequisites
Before you begin, ensure you have:
-- Docker installed on your system
-- An OpenAI API key (for LLM operations)
-- A FalkorDB instance running (or use the bundled Docker setup)
+- Docker and Docker Compose installed on your system
+- At least one LLM provider API key:
+ - OpenAI API key (recommended)
+ - Or Anthropic, Gemini, Groq, or Azure OpenAI API key
+- (Optional) Python 3.10+ if running the MCP server standalone with an external FalkorDB instance
-## Quick Start with Docker
+## Quick Start with Docker Compose
-The easiest way to run the Graphiti MCP Server with FalkorDB is using Docker:
+The easiest way to run the Graphiti MCP Server with FalkorDB is using the official Docker Compose configuration from [Zep's Graphiti repository](https://github.com/getzep/graphiti/tree/main/mcp_server).
-### Step 1: Pull the Docker Image
+### Option 1: Combined Image (Recommended)
+
+This setup uses a single container that includes both FalkorDB and the MCP server.
+
+1. **Create a directory for your setup:**
```bash
-docker pull falkordb/graphiti-knowledge-graph-mcp:latest
+mkdir graphiti-mcp && cd graphiti-mcp
```
-### Step 2: Run the MCP Server
+2. **Download the docker-compose configuration:**
-Run the server with required environment variables:
+```bash
+curl -O https://raw.githubusercontent.com/getzep/graphiti/main/mcp_server/docker/docker-compose.yml
+```
+
+3. **Create a `.env` file with your API key:**
+
+```env
+OPENAI_API_KEY=your-openai-api-key
+FALKORDB_PASSWORD=
+GRAPHITI_GROUP_ID=main
+```
+
+4. **Start the services:**
```bash
-docker run -d \
- --name graphiti-mcp \
- -e OPENAI_API_KEY="your-openai-api-key" \
- -e DATABASE_TYPE="falkordb" \
- -e FALKORDB_HOST="host.docker.internal" \
- -e FALKORDB_PORT="6379" \
- -p 8000:8000 \
- falkordb/graphiti-knowledge-graph-mcp:latest
+docker-compose up -d
```
-**Note**: If you're running FalkorDB on your local machine, use `host.docker.internal` as the `FALKORDB_HOST` to allow the container to access your host's localhost.
+The combined image will start both FalkorDB and the MCP server in a single container, accessible at:
+- **FalkorDB (Redis):** `localhost:6379`
+- **FalkorDB Browser UI:** `http://localhost:3000`
+- **MCP Server HTTP endpoint:** `http://localhost:8000/mcp/`
+- **Health check:** `http://localhost:8000/health`
+
+### Option 2: Separate Containers
-#### Alternative: Using a .env File
+For more flexibility, you can run FalkorDB and the MCP server in separate containers.
-For easier management of environment variables, create a `.env` file:
+1. **Create a directory and download the configuration:**
+
+```bash
+mkdir graphiti-mcp && cd graphiti-mcp
+curl -O https://raw.githubusercontent.com/getzep/graphiti/main/mcp_server/docker/docker-compose-falkordb.yml
+mv docker-compose-falkordb.yml docker-compose.yml
+```
+
+2. **Create a `.env` file:**
```env
OPENAI_API_KEY=your-openai-api-key
-DATABASE_TYPE=falkordb
-FALKORDB_HOST=host.docker.internal
-FALKORDB_PORT=6379
-FALKORDB_USERNAME=
+FALKORDB_URI=redis://falkordb:6379
FALKORDB_PASSWORD=
+FALKORDB_DATABASE=default_db
+GRAPHITI_GROUP_ID=main
```
-Then run the container with the `--env-file` option:
+3. **Start the services:**
```bash
-docker run -d \
- --name graphiti-mcp \
- --env-file .env \
- -p 8000:8000 \
- falkordb/graphiti-knowledge-graph-mcp:latest
+docker-compose up -d
```
-### Step 3: Run FalkorDB (if needed)
+This configuration starts FalkorDB and the MCP server as separate containers with the same accessible ports as the combined image.
+
+## Manual Docker Setup (Alternative)
-If you don't have a FalkorDB instance running, start one:
+If you prefer to run containers manually without Docker Compose, you can use the standalone MCP server image:
+
+### Step 1: Run FalkorDB
```bash
docker run -d \
@@ -94,89 +121,106 @@ docker run -d \
falkordb/falkordb:latest
```
-## Docker Compose Setup
-
-For a complete setup with both FalkorDB and the MCP server, create a `docker-compose.yml`:
-
-```yaml
-version: '3.8'
-
-services:
- falkordb:
- image: falkordb/falkordb:latest
- ports:
- - "6379:6379" # Redis protocol port
- - "3000:3000" # FalkorDB Browser UI
- volumes:
- - falkordb-data:/data
-
- graphiti-mcp:
- image: falkordb/graphiti-knowledge-graph-mcp:latest
- depends_on:
- - falkordb
- ports:
- - "8000:8000" # MCP Server HTTP/SSE port
- environment:
- - OPENAI_API_KEY=${OPENAI_API_KEY}
- - DATABASE_TYPE=falkordb
- - FALKORDB_HOST=falkordb
- - FALKORDB_PORT=6379
- - FALKORDB_USERNAME=${FALKORDB_USERNAME:-}
- - FALKORDB_PASSWORD=${FALKORDB_PASSWORD:-}
-
-volumes:
- falkordb-data:
+### Step 2: Run the MCP Server
+
+```bash
+docker run -d \
+ --name graphiti-mcp \
+ -e OPENAI_API_KEY="your-openai-api-key" \
+ -e FALKORDB_URI="redis://host.docker.internal:6379" \
+ -e FALKORDB_PASSWORD="" \
+ -e FALKORDB_DATABASE="default_db" \
+ -e GRAPHITI_GROUP_ID="main" \
+ -p 8000:8000 \
+ zepai/knowledge-graph-mcp:standalone
```
-Create a `.env` file in the same directory:
+**Note**: Use `host.docker.internal` as the hostname to allow the container to access FalkorDB running on your host machine.
+
+## Configuration
+
+The Graphiti MCP server can be configured using environment variables in a `.env` file or through a `config.yaml` file.
+
+### Default Configuration
+The MCP server comes with sensible defaults:
+- **Transport**: HTTP (accessible at `http://localhost:8000/mcp/`)
+- **Database**: FalkorDB (combined in single container with MCP server)
+- **LLM**: OpenAI with model gpt-4o-mini
+- **Embedder**: OpenAI text-embedding-3-small
+
+### LLM Provider Configuration
+
+The server supports multiple LLM providers. Set the appropriate API key in your `.env` file:
+
+**OpenAI (default)**:
```env
-OPENAI_API_KEY=your-openai-api-key
-DATABASE_TYPE=falkordb
-FALKORDB_USERNAME=
-FALKORDB_PASSWORD=
+OPENAI_API_KEY=sk-proj-your-key-here
```
-Then start both services:
+**Anthropic**:
+```env
+ANTHROPIC_API_KEY=your-anthropic-key
+```
-```bash
-docker-compose up -d
+**Google Gemini**:
+```env
+GOOGLE_API_KEY=your-google-key
```
-## Configuration
+**Groq**:
+```env
+GROQ_API_KEY=your-groq-key
+```
+
+**Azure OpenAI**:
+```env
+AZURE_OPENAI_API_KEY=your-azure-key
+AZURE_OPENAI_ENDPOINT=your-endpoint-url
+AZURE_OPENAI_DEPLOYMENT=your-deployment-name
+```
### Environment Variables
-The MCP server accepts the following environment variables:
+Key environment variables for the MCP server:
| Variable | Description | Default | Required | Example |
|----------|-------------|---------|----------|---------|
-| `OPENAI_API_KEY` | Your OpenAI API key for LLM operations | - | Yes | `sk-proj-...` |
-| `DATABASE_TYPE` | Database backend type (must be "falkordb") | - | Yes | `falkordb` |
-| `FALKORDB_HOST` | FalkorDB server hostname | `localhost` | No | `host.docker.internal` |
-| `FALKORDB_PORT` | FalkorDB server port | `6379` | No | `6379` |
-| `FALKORDB_USERNAME` | FalkorDB username (if authentication enabled) | - | No | `default` |
+| `OPENAI_API_KEY` | OpenAI API key (or use another LLM provider) | - | Yes* | `sk-proj-...` |
+| `FALKORDB_URI` | FalkorDB connection URI | `redis://localhost:6379` | No | `redis://falkordb:6379` |
| `FALKORDB_PASSWORD` | FalkorDB password (if authentication enabled) | - | No | `your-password` |
-| `PORT` | MCP server port | `8000` | No | `8000` |
-| `MODEL_NAME` | OpenAI model to use | `gpt-4o-mini` | No | `gpt-5` |
+| `FALKORDB_DATABASE` | Database name | `default_db` | No | `default_db` |
+| `SEMAPHORE_LIMIT` | Episode processing concurrency limit | `10` | No | `10` |
+| `BROWSER` | Enable FalkorDB Browser UI (combined image) | `1` | No | `1` |
+
+*At least one LLM provider API key is required
+
+### Concurrency and Rate Limits
+
+The `SEMAPHORE_LIMIT` controls how many episodes can be processed simultaneously. Adjust based on your LLM provider tier:
+
+- **OpenAI Tier 1 (free)**: `SEMAPHORE_LIMIT=1-2`
+- **OpenAI Tier 2**: `SEMAPHORE_LIMIT=5-8`
+- **OpenAI Tier 3**: `SEMAPHORE_LIMIT=10-15`
+- **OpenAI Tier 4**: `SEMAPHORE_LIMIT=20-50`
+- **Anthropic default**: `SEMAPHORE_LIMIT=5-8`
+
+If you see 429 rate limit errors, reduce the value. Monitor your LLM provider's dashboard for actual request rates.
### FalkorDB Cloud Configuration
-To use FalkorDB Cloud with the MCP server:
+To use FalkorDB Cloud with the MCP server, update your `.env` file:
-```bash
-docker run -d \
- --name graphiti-mcp \
- -e OPENAI_API_KEY="your-openai-api-key" \
- -e DATABASE_TYPE="falkordb" \
- -e FALKORDB_HOST="your-instance.falkordb.cloud" \
- -e FALKORDB_PORT="6379" \
- -e FALKORDB_USERNAME="default" \
- -e FALKORDB_PASSWORD="your-cloud-password" \
- -p 8000:8000 \
- falkordb/graphiti-knowledge-graph-mcp:latest
+```env
+OPENAI_API_KEY=your-openai-api-key
+FALKORDB_URI=redis://your-instance.falkordb.cloud:6379
+FALKORDB_PASSWORD=your-cloud-password
+FALKORDB_DATABASE=default_db
+GRAPHITI_GROUP_ID=main
```
+Then use the docker-compose configuration with the separate containers option (docker-compose-falkordb.yml), as it's designed for external database connections.
+
## Client Integration
### Claude Desktop
@@ -193,35 +237,37 @@ Add the following configuration:
{
"mcpServers": {
"graphiti-memory": {
- "transport": "sse",
- "url": "http://localhost:8000/sse"
+ "transport": "http",
+ "url": "http://localhost:8000/mcp/"
}
}
}
```
-**Note**: The MCP server uses Server-Sent Events (SSE) for real-time communication between the AI client and the knowledge graph. The `OPENAI_API_KEY` is already configured in the MCP server's Docker environment, so you don't need to specify it again here.
+**Note**: The MCP server uses HTTP transport by default with the endpoint at `/mcp/`. The `OPENAI_API_KEY` is already configured in the MCP server's Docker environment, so you don't need to specify it again here.
+
+**Alternative (stdio transport)**: If you have the Graphiti repository cloned locally and Python installed, you can use stdio transport for better integration with some clients. See the [official Graphiti documentation](https://github.com/getzep/graphiti/blob/main/mcp_server/README.md#integrating-with-mcp-clients) for stdio configuration details.
**After configuration**:
1. Restart Claude Desktop to apply the changes
2. Look for the MCP server indicator in Claude's interface
3. Claude will now have access to persistent memory through the knowledge graph
-### Cursor IDE
+### Cursor IDE and VS Code
-For Cursor IDE, add the MCP server configuration to your Cursor settings:
+For Cursor IDE and VS Code with GitHub Copilot, add the MCP server configuration:
-1. Open Cursor IDE settings
-2. Navigate to the MCP configuration section
-3. Add the server configuration:
+**Cursor IDE**: Add to Cursor settings
+
+**VS Code**: Add to `.vscode/mcp.json` or global settings
```json
{
- "mcp": {
- "servers": {
- "graphiti-memory": {
- "url": "http://localhost:8000",
- "transport": "sse"
+ "mcpServers": {
+ "graphiti-memory": {
+ "uri": "http://localhost:8000/mcp/",
+ "transport": {
+ "type": "http"
}
}
}
@@ -263,25 +309,36 @@ Once configured, test the connection with these steps:
The AI will use the Graphiti MCP server to store and retrieve this information from the FalkorDB knowledge graph.
-## MCP Server Capabilities
+## Available Tools
+
+The Graphiti MCP server exposes the following tools to AI clients:
+
+- **`add_episode`**: Add an episode to the knowledge graph (supports text, JSON, and message formats)
+- **`search_nodes`**: Search the knowledge graph for relevant node summaries
+- **`search_facts`**: Search the knowledge graph for relevant facts (edges between entities)
+- **`delete_entity_edge`**: Delete an entity edge from the knowledge graph
+- **`delete_episode`**: Delete an episode from the knowledge graph
+- **`get_entity_edge`**: Get an entity edge by its UUID
+- **`get_episodes`**: Get the most recent episodes for a specific group
+- **`clear_graph`**: Clear all data from the knowledge graph and rebuild indices
-The Graphiti MCP server exposes the following capabilities to AI clients:
+### Entity Types
-### Tools
+Graphiti MCP Server includes built-in entity types for structured knowledge extraction. The MCP server automatically uses these entity types during episode ingestion to extract and structure information from conversations and documents.
-- **`add_episode`**: Store new information as an episode in the knowledge graph
- - Extracts entities and relationships
- - Adds temporal context
- - Links to existing knowledge
+**Available Entity Types:**
-- **`search`**: Query the knowledge graph for relevant information
- - Semantic search using embeddings
- - Graph traversal for connected information
- - Temporal filtering
+- **Preference**: User preferences, choices, opinions, or selections (prioritized for user-specific information)
+- **Requirement**: Specific needs, features, or functionality that must be fulfilled
+- **Procedure**: Standard operating procedures and sequential instructions
+- **Location**: Physical or virtual places where activities occur
+- **Event**: Time-bound activities, occurrences, or experiences
+- **Organization**: Companies, institutions, groups, or formal entities
+- **Document**: Information content in various forms (books, articles, reports, videos, etc.)
+- **Topic**: Subject of conversation, interest, or knowledge domain (used as a fallback)
+- **Object**: Physical items, tools, devices, or possessions (used as a fallback)
-- **`get_context`**: Retrieve contextual information for a conversation
- - Builds relevant context from the graph
- - Returns connected entities and relationships
+These entity types can be customized in the `config.yaml` file if you're running the MCP server from source.
### Graph Schema
@@ -305,16 +362,17 @@ The Graphiti MCP server stores information in FalkorDB using the following schem
### Programmatic Access
{: .warning }
-> **Important**: The Graphiti MCP server is designed to be used by MCP clients (like Claude Desktop or Cursor) via the Server-Sent Events (SSE) transport protocol. It does **not** expose HTTP REST API endpoints for direct programmatic access.
+> **Important**: The Graphiti MCP server is designed to be used by MCP clients (like Claude Desktop or Cursor) via the HTTP transport protocol. It does **not** expose direct REST API endpoints outside of the MCP protocol.
-The server only exposes:
-- `/sse` - Server-Sent Events endpoint for MCP protocol communication
+The server exposes:
+- `/mcp/` - HTTP MCP protocol endpoint
+- `/health` - Health check endpoint
To interact with the Graphiti knowledge graph programmatically, you have two options:
**Option 1: Use an MCP Client Library**
-Use an MCP client library that implements the MCP protocol to communicate with the server via SSE. This is the intended way to interact with the server programmatically.
+Use an MCP client library that implements the MCP protocol to communicate with the server via HTTP. This is the intended way to interact with the server programmatically.
**Option 2: Access FalkorDB Directly**
@@ -373,16 +431,32 @@ for record in result.result_set:
### View Server Logs
-To view the MCP server logs:
+To view the logs:
+
+**For combined image:**
+```bash
+docker logs -f graphiti-falkordb
+```
+**For separate containers:**
```bash
+# MCP server logs
docker logs -f graphiti-mcp
+
+# FalkorDB logs
+docker logs -f falkordb
```
### Check FalkorDB Connection
Verify the connection to FalkorDB using the Redis CLI:
+**For combined image:**
+```bash
+docker exec -it graphiti-falkordb redis-cli PING
+```
+
+**For separate containers:**
```bash
# Test from the FalkorDB container
docker exec -it falkordb redis-cli PING
@@ -391,7 +465,7 @@ docker exec -it falkordb redis-cli PING
docker exec -it graphiti-mcp redis-cli -h falkordb -p 6379 PING
```
-Both commands should return `PONG` if the connection is successful.
+All commands should return `PONG` if the connection is successful.
### Inspect the Knowledge Graph
@@ -414,10 +488,11 @@ MATCH (n) RETURN n LIMIT 25
**Solutions**:
- Verify FalkorDB is running: `docker ps | grep falkordb`
- Test FalkorDB connection: `docker exec -it redis-cli PING` (should return `PONG`)
-- Check network connectivity: Use `host.docker.internal` for local FalkorDB when running MCP server in Docker
+- Check the `FALKORDB_URI` format: `redis://hostname:port`
+- For separate containers, use the service name: `redis://falkordb:6379`
+- For external FalkorDB, use `redis://host.docker.internal:6379`
- Verify port 6379 is accessible
- Check firewall settings
-- Verify `DATABASE_TYPE=falkordb` environment variable is set (server won't start without it)
### Authentication Errors
@@ -443,9 +518,10 @@ MATCH (n) RETURN n LIMIT 25
**Problem**: Claude Desktop or Cursor cannot connect to MCP server
**Solutions**:
-- Verify the MCP server is running: `docker ps | grep graphiti-mcp`
-- Check the server logs: `docker logs graphiti-mcp`
-- Test the SSE endpoint: `curl http://localhost:8000/sse`
+- Verify the MCP server is running: `docker ps | grep graphiti`
+- Check the server logs: `docker logs graphiti-mcp` (or `docker logs graphiti-falkordb` for combined image)
+- Test the MCP endpoint: `curl http://localhost:8000/mcp/`
+- Check the health endpoint: `curl http://localhost:8000/health`
- Ensure the configuration file path is correct for your OS
- Restart the client application after changing configuration
- Check for port conflicts on port 8000: `lsof -i :8000` (macOS/Linux) or `netstat -ano | findstr :8000` (Windows)
@@ -484,7 +560,8 @@ MATCH (n) RETURN n LIMIT 25
## Resources
-- π³ [Docker Hub Repository](https://hub.docker.com/r/falkordb/graphiti-knowledge-graph-mcp)
+- π³ [Graphiti MCP Server Docker Setup](https://github.com/getzep/graphiti/tree/main/mcp_server/docker)
+- π¦ [Docker Hub Repository](https://hub.docker.com/r/zepai/knowledge-graph-mcp)
- π [Model Context Protocol Documentation](https://modelcontextprotocol.io/)
- π [Graphiti Documentation](https://help.getzep.com/graphiti/)
- π» [Graphiti GitHub Repository](https://github.com/getzep/graphiti)
diff --git a/algorithms/index.md b/algorithms/index.md
index a23e57f7..8d00790a 100644
--- a/algorithms/index.md
+++ b/algorithms/index.md
@@ -3,6 +3,9 @@ title: "Algorithms"
description: Graph Algorithms Overview
nav_order: 3
has_children: true
+redirect_from:
+ - /cypher/algorithms.html
+ - /cypher/algorithms
---
# FalkorDB Algorithms Overview
@@ -31,6 +34,9 @@ This overview summarizes the available algorithms and links to their individual
- **[SSpath](./sspath.md)**
Enumerates all paths from a single source node to other nodes, based on constraints like edge filters and depth.
+- **[MSF](./msf.md)**
+ Computes the Minimum Spanning Forest of a graph, finding the minimum spanning tree for each connected component.
+
For path expressions like `shortestPath()` used directly in Cypher queries, refer to the [Cypher Path Functions section](../cypher/functions.md#path-functions).
## Centrality Measures
diff --git a/algorithms/msf.md b/algorithms/msf.md
new file mode 100644
index 00000000..ea5b6783
--- /dev/null
+++ b/algorithms/msf.md
@@ -0,0 +1,177 @@
+---
+title: "MSF"
+description: "Minimum Spanning Forest Algorithm"
+parent: "Algorithms"
+nav_order: 9
+---
+
+# Minimum Spanning Forest (MSF)
+
+The Minimum Spanning Forest algorithm computes the minimum spanning forest of a graph. A minimum spanning forest is a collection of minimum spanning trees, one for each connected component in the graph.
+
+## What is a Minimum Spanning Forest?
+
+- For a **connected graph**, the MSF is a single minimum spanning tree (MST) that connects all nodes with the minimum total edge weight
+- For a **disconnected graph**, the MSF consists of multiple MSTs, one for each connected component
+- The forest contains no cycles and has exactly `N - C` edges, where `N` is the number of nodes and `C` is the number of connected components
+
+## Use Cases
+
+- **Network Design**: Minimize cable/pipeline costs when connecting multiple locations
+- **Clustering**: Identify natural groupings in data by analyzing the forest structure
+- **Image Segmentation**: Group similar pixels using edge weights as similarity measures
+- **Road Networks**: Optimize road construction to connect all cities with minimum cost
+
+## Syntax
+
+```cypher
+CALL algo.MSF(
+ config: MAP
+) YIELD src, dest, weight, relationshipType
+```
+
+### Parameters
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `config` | MAP | Configuration map containing algorithm parameters |
+
+#### Configuration Options
+
+| Option | Type | Required | Default | Description |
+|--------|------|----------|---------|-------------|
+| `sourceNodes` | List of Nodes | No | All nodes | Starting nodes for the algorithm. If not provided, all nodes in the graph are considered |
+| `relationshipTypes` | List of Strings | No | All types | Relationship types to traverse. If not provided, all relationship types are considered |
+| `relationshipWeightProperty` | String | No | `null` | Property name containing edge weights. If not specified, all edges have weight 1.0 |
+| `defaultValue` | Float | No | `1.0` | Default weight for edges that don't have the weight property |
+
+### Returns
+
+| Field | Type | Description |
+|-------|------|-------------|
+| `src` | Node | Source node of the edge in the spanning forest |
+| `dest` | Node | Destination node of the edge in the spanning forest |
+| `weight` | Float | Weight of the edge |
+| `relationshipType` | String | Type of the relationship |
+
+## Examples
+
+### Example 1: Basic MSF with Unweighted Graph
+
+Find the minimum spanning forest treating all edges equally:
+
+```cypher
+CALL algo.MSF({}) YIELD src, dest, weight, relationshipType
+RETURN src.name AS source, dest.name AS destination, weight, relationshipType
+```
+
+### Example 2: MSF with Weighted Edges
+
+Consider a graph representing cities connected by roads with distances:
+
+```cypher
+// Create a weighted graph
+CREATE (a:City {name: 'A'}), (b:City {name: 'B'}), (c:City {name: 'C'}),
+ (d:City {name: 'D'}), (e:City {name: 'E'})
+CREATE (a)-[:ROAD {distance: 2}]->(b),
+ (a)-[:ROAD {distance: 3}]->(c),
+ (b)-[:ROAD {distance: 1}]->(c),
+ (b)-[:ROAD {distance: 4}]->(d),
+ (c)-[:ROAD {distance: 5}]->(d),
+ (d)-[:ROAD {distance: 6}]->(e)
+
+// Find minimum spanning forest using distance weights
+CALL algo.MSF({
+ relationshipWeightProperty: 'distance'
+}) YIELD src, dest, weight
+RETURN src.name AS from, dest.name AS to, weight AS distance
+ORDER BY weight
+```
+
+**Result:**
+```text
+from | to | distance
+-----|----|---------
+B | C | 1.0
+A | B | 2.0
+A | C | 3.0
+B | D | 4.0
+D | E | 6.0
+```
+
+### Example 3: MSF on Specific Relationship Types
+
+Find the spanning forest considering only specific relationship types:
+
+```cypher
+CALL algo.MSF({
+ relationshipTypes: ['ROAD', 'HIGHWAY'],
+ relationshipWeightProperty: 'distance'
+}) YIELD src, dest, weight, relationshipType
+RETURN src.name AS from, dest.name AS to, weight, relationshipType
+```
+
+### Example 4: MSF Starting from Specific Nodes
+
+Compute the spanning forest starting from a subset of nodes:
+
+```cypher
+MATCH (start:City) WHERE start.name IN ['A', 'B']
+WITH collect(start) AS startNodes
+CALL algo.MSF({
+ sourceNodes: startNodes,
+ relationshipWeightProperty: 'distance'
+}) YIELD src, dest, weight
+RETURN src.name AS from, dest.name AS to, weight
+```
+
+### Example 5: Disconnected Graph
+
+For a graph with multiple components, MSF returns multiple trees:
+
+```cypher
+// Create two disconnected components
+CREATE (a:Node {name: 'A'})-[:CONNECTED {weight: 1}]->(b:Node {name: 'B'}),
+ (b)-[:CONNECTED {weight: 2}]->(c:Node {name: 'C'}),
+ (x:Node {name: 'X'})-[:CONNECTED {weight: 3}]->(y:Node {name: 'Y'})
+
+// Find MSF
+CALL algo.MSF({
+ relationshipWeightProperty: 'weight'
+}) YIELD src, dest, weight
+RETURN src.name AS from, dest.name AS to, weight
+```
+
+**Result:** Two separate trees (A-B-C and X-Y)
+
+## Algorithm Details
+
+FalkorDB's MSF implementation uses an efficient matrix-based approach optimized for graph databases:
+
+1. **Connected Components**: First identifies all connected components in the graph
+2. **MST per Component**: Computes a minimum spanning tree for each component using a variant of Kruskal's or Prim's algorithm
+3. **Edge Selection**: Selects edges in order of increasing weight, avoiding cycles
+
+### Performance Characteristics
+
+- **Time Complexity**: O(E log V) where E is the number of edges and V is the number of vertices
+- **Space Complexity**: O(V + E)
+- **Optimized**: Uses sparse matrix representation for efficient computation
+
+## Best Practices
+
+1. **Weight Properties**: Ensure weight properties are numeric (integers or floats)
+2. **Missing Weights**: Use `defaultValue` to handle edges without weight properties
+3. **Large Graphs**: For large graphs (100K+ nodes), consider filtering by `sourceNodes` or `relationshipTypes`
+4. **Directed vs Undirected**: The algorithm treats relationships as undirected for spanning forest purposes
+
+## Related Algorithms
+
+- **[WCC (Weakly Connected Components)](./wcc.md)**: Identify connected components before running MSF
+- **[BFS](./bfs.md)**: Traverse the resulting spanning forest
+- **[SPpath](./sppath.md)**: Find shortest paths using the spanning forest structure
+
+## See Also
+
+- [Cypher Procedures](../cypher/procedures.md)
+- [Graph Algorithms Overview](./index.md)
diff --git a/browser/readme-browser.md b/browser/readme-browser.md
new file mode 100644
index 00000000..300c9758
--- /dev/null
+++ b/browser/readme-browser.md
@@ -0,0 +1,130 @@
+---
+title: "Browser"
+description: "FalkorDB Browser web UI documentation"
+nav_order: 9
+permalink: /browser/
+---
+
+# FalkorDB Graph Visualization Tool (Browser)
+FalkorDB's Browser provides a web UI for exploring, querying, and managing FalkorDB graphs. It allows developers to interact with graphs loaded to FalkorDB, explore how specific queries behave, and review the current data model. FalkorDB Browser integrates within the main FalkorDB Docker container and through the Cloud service.
+
+
+
+---
+
+## Main Features
+
+### Graph exploration (Graph page)
+| Feature | Description |
+| --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| Interactive graph canvas | Visualizes query results containing nodes and edges as an interactive graph. Supports pan, zoom, and interaction with nodes and relationships. Toggles visibility by labels and relationship types. |
+| Element search (in-canvas search) | Search nodes and edges by node properties (string prefix match), IDs, relationship type, and labels. Jump to, zoom to, and select the match. |
+| Data and inspection panel | Selecting an element opens a side panel for inspecting its properties. This panel supports editing workflows (see "Data manipulation"). |
+| Entity Creation Tools | Add a node, an edge, or both to the current graph from the canvas view. |
+
+### Querying
+| Feature | Description |
+| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| Cypher query editor (Monaco) | The editor-style experience for writing Cypher includes keyboard shortcuts: Run (Enter and Cmd/Ctrl + Enter in the query-history editor) and Insert newline (Shift + Enter). The editor includes Cypher keyword and function completion based on the Browser's built-in lists. |
+| Results views | Graph view for node and edge results. Table view for tabular results. |
+| Query metadata | The Metadata tab shows query metadata text, explain plan (rendered as a nested tree), and profile output (rendered as a nested tree). |
+
+### Query history
+| Feature | Description |
+| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- |
+| Persistent query history | Stores in browser localStorage. |
+| History browser dialog | Allows you to search and filter previous queries, filter by graph name, and delete single queries, multi-select delete, or delete all queries. |
+| Per-query metadata | Review metadata, explain, and profile for past queries. |
+
+
+
+### Data manipulation (nodes/relationships)
+| Feature | Description |
+| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
+| Create and delete operations | Create node and create relationship flows from the Graph UI. Delete elements (node or relationship) from the Graph UI. |
+| Edit labels | Edit labels through API routes (the UI provides label management components). |
+
+### Graph management
+| Feature | Description |
+| ---------------- | -------------------------------------------------------------------------------------------------------- |
+| Create graphs | Create graphs from the UI. |
+| Delete graphs | Delete graphs (supports deleting multiple selected graphs). |
+| Duplicate graphs | Create a copy of an existing graph (including data). |
+| Export graphs | Download a .dump file via the Browser (/api/graph/:graph/export). |
+| Upload data | Upload data through the "Upload Data" dialog, which supports drag-and-drop file selection (Dropzone UI). |
+
+### Graph Info panel
+| Feature | Description |
+| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| Memory Usage tracking | Exposes current memory utilization of the graph in MB. |
+| Node Label tracking | Displays all node labels in the graph and controls style visualization for labels. Click on a node label to trigger a query that visualizes nodes from this label. |
+| Edge Type tracking | Displays all edge types in the graph. Click on an edge type to trigger a graph query showing only nodes connected through this edge type. |
+| Property Keys tracking | Displays all property keys in the graph. Click on a key to issue a query that shows nodes and edges where the property exists (not NULL). |
+
+
+---
+
+### API Documentation
+| Feature | Description |
+| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| Built-in Swagger UI | Available at /docs. Loads the Browser's OpenAPI spec from /api/swagger. "Try it out" enabled. Adds an X-JWT-Only: true header when calling endpoints from Swagger UI. |
+
+
+
+
+### Authentication & access control
+| Feature | Description |
+| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
+| Authentication | Uses NextAuth (credentials-backed) for authentication. |
+| Role-aware UI capabilities | Read-Only users cannot create graphs. Admin users can access database configuration and user-management sections in settings. |
+
+### Settings
+| Section | Description |
+| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| Browser settings | Query execution defaults and limits: timeout, result limit, run default query on load. User experience: content persistence (auto-save and restore), display-text priority (controls which node property appears as the node caption). Graph info refresh interval. Tutorial replay. |
+| DB configurations (Admin) | View and update server configuration values. Some runtime configurations remain read-only. |
+| Users (Admin) | List users and adjust roles. Add and delete users. |
+| Personal Access Tokens | Generate tokens (with optional expiration). Tokens appear once at creation (copy-to-clipboard UX). Revoke existing tokens. |
+
+
+---
+
+## Common Workflows
+### Running and visualizing queries
+| Step | Action |
+| ---- | -------------------------------------------------------------------------------------- |
+| 1 | Go to Graphs and select a graph. |
+| 2 | Write a Cypher query in the editor and run it. |
+| 3 | Inspect results in the Graph tab (interactive canvas) or Table tab (rows and columns). |
+| 4 | Use Labels and Relationships toggles to focus the canvas. |
+
+[NEED GIF HERE]
+
+### Inspecting and editing elements
+| Step | Action |
+| ---- | -------------------------------------------------------------------------------------- |
+| 1 | Click a node or edge in the canvas. |
+| 2 | Use the Data panel to inspect properties and apply create or delete actions as needed. |
+
+### Working with query history
+| Step | Action |
+| ---- | ---------------------------------------------------------------------- |
+| 1 | Open Query History and filter by graph or search for a previous query. |
+| 2 | Select a query and review Metadata, Explain, or Profile. |
+
+[NEED GIF HERE]
+
+### Exporting graph data
+| Step | Action |
+| ---- | ------------------------------------------- |
+| 1 | Open graph management and select a graph. |
+| 2 | Click Export Data to download a `.dump` file. |
+
+[NEED GIF HERE]
+
diff --git a/cloud/enterprise-tier.md b/cloud/enterprise-tier.md
new file mode 100644
index 00000000..7b11fdf4
--- /dev/null
+++ b/cloud/enterprise-tier.md
@@ -0,0 +1,52 @@
+---
+title: "Enterprise Tier"
+parent: "Cloud DBaaS"
+nav_order: 4
+description: "FalkorDB DBaaS Enterprise Tier"
+---
+
+
+
+
+# Enterprise Tier
+FalkorDB's **Enterprise Tier** is designed for the most demanding workloads, offering ultimate performance, scale, and customization, with pricing determined on a **Custom** basis. This tier includes **every available enterprise feature**, such as **VPC Peering**, **Advanced Monitoring**, and **Dedicated Account Manager** support.
+
+The Enterprise Tier is fully optimized for mission-critical applications, providing the highest levels of security, availability, and dedicated operational support. Deployment configurations are tailored to your specific infrastructure, scale, and compliance requirements.
+
+## FalkorDB Pricing Plans Comparison
+
+| Feature | FREE | STARTUP | PRO | ENTERPRISE |
+| :--- | :---: | :---: | :---: | :---: |
+| **Monthly Cost (from)** | **Free** | **$73** | **$350** | **Custom** |
+| Multi-Graph / Multi-Tenancy | β | β | β | **π’** |
+| Graph Access Control | β | β | β | **π’** |
+| **TLS** | β | β | β | **π’** |
+| **VPC** | β | β | β | **π’** |
+| Cluster Deployment | β | β | β | **π’** |
+| High Availability | β | β | β | **π’** |
+| Multi-zone Deployment | β | β | β | **π’** |
+| Scalability | β | β | β | **π’** |
+| Continuous Persistence | β | β | β | **π’** |
+| **Automated Backups** | β | Every 12 Hours | Every 12 Hours | **Every Hour** |
+| **Advanced Monitoring** | β | β | β | **π’** |
+| **Support** | Community | Community | 24/7 | **Dedicated** |
+| **Dedicated Account Manager** | β | β | β | **π’** |
+| **Cloud Providers** | AWS, GCP, Azure | AWS, GCP, Azure | AWS, GCP, Azure | **AWS, GCP, Azure** |
+
+## Terms
+### Consultation and Pricing
+> The Enterprise Tier is customized to your specific needs, leveraging dedicated resources, tailored support SLAs, and private deployment options. Pricing is calculated based on the custom configuration of cores, memory, and additional enterprise components.
+>
+> **For precise pricing, deployment details, and a dedicated consultation:**
+> **[Contact our Sales Team](https://www.falkordb.com/get-a-demo/)**
+>
+> β οΈ Prices are subject to change
+
+## Getting Started
+
+
+
+
+
+βοΈ To begin your Enterprise journey, schedule a consultation:
+[](mailto:info@falkordb.com)
diff --git a/cloud/features.md b/cloud/features.md
new file mode 100644
index 00000000..72f8617b
--- /dev/null
+++ b/cloud/features.md
@@ -0,0 +1,63 @@
+---
+title: "Features"
+parent: "Cloud DBaaS"
+nav_order: 5
+description: "FalkorDB DBaaS Features"
+---
+
+# Features
+
+## Multi-Tenancy
+Multi-tenancy lets you run multiple isolated graph databases within a single FalkorDB instance. Each tenant operates independently with its own data, queries, and access controls while sharing the underlying infrastructure.
+
+Developers building SaaS applications need multi-tenancy to serve multiple customers without deploying separate database instances for each one. This approach reduces operational overhead and infrastructure costs while maintaining strict data isolation between tenants.
+
+In practice, you create distinct graph databases for each customer or project, and FalkorDB handles the isolation automatically.
+
+## Cloud Providers
+### AWS
+FalkorDB runs on Amazon Web Services infrastructure, giving you access to AWS's global network of data centers and integration with other AWS services. You can deploy FalkorDB instances in several AWS regions and connect them to your existing AWS resources.
+
+Teams already using AWS benefit from keeping their graph database in the same cloud environment as their applications. This setup reduces latency and simplifies network configuration since your services communicate within the AWS network.
+
+When you deploy on AWS, you choose your preferred region, and FalkorDB provisions the necessary compute and storage resources in that location.
+
+### Google Cloud Platform (GCP)
+FalkorDB integrates with Google Cloud Platform, allowing you to run graph databases on Google's infrastructure. You gain access to GCP's global network and can combine FalkorDB with other Google Cloud services.
+
+Organizations using GCP for their applications should deploy FalkorDB in the same cloud to maintain consistent infrastructure management. Keeping your database and applications on GCP reduces cross-cloud data transfer costs and latency.
+
+You select a GCP region during deployment, and FalkorDB sets up your graph database instance within Google's infrastructure.
+
+> Note: Microsoft Azure is currently available in a Bring-Your-Own-Cloud configuration
+
+## TLS
+TLS (Transport Layer Security) encrypts all data transmitted between your application and FalkorDB. This encryption prevents anyone intercepting network traffic from reading your queries or results.
+
+Applications handling sensitive data must use TLS to protect information in transit. Without encryption, credentials, personal data, and business logic become vulnerable when traveling across networks.
+
+When you enable TLS, FalkorDB requires encrypted connections. Your application must configure its database client to use TLS, and all communication happens over secure channels.
+
+## VPC
+A Virtual Private Cloud (VPC) creates an isolated network environment where your FalkorDB instance runs separately from the public internet. Only resources within your VPC or those you explicitly authorize can reach your database.
+
+Organizations with security requirements need VPC deployment to control network access to their databases. VPCs prevent unauthorized connection attempts and give you granular control over which services can communicate with FalkorDB.
+
+You deploy FalkorDB into your existing VPC, and the database becomes accessible only through your private network. Your applications connect using private IP addresses instead of public endpoints.
+
+## Persistence
+Persistence ensures your graph data survives system restarts, crashes, or failures by writing changes to disk. Without persistence, you lose all data when the database stops.
+
+Any application storing important data requires persistence to maintain durability. In-memory-only databases lose everything during unexpected shutdowns, making them unsuitable for production workloads.
+
+FalkorDB persists data through regular snapshots and transaction logs. These mechanisms guarantee that committed transactions remain safe even if the system crashes immediately afterward.
+
+## Graph Browser
+You can connect to the falkordb browser (integrated into your web browser) from the cloud console. The browser allows visualizing query results, allows you to traverse the graph and more. Multi Graph support is enabled by default in the browser which simplifies navigation and data management.
+
+### Solution Architecture
+Solution architecture support helps you design how FalkorDB integrates with your broader application infrastructure. This guidance covers connection patterns, data modeling approaches, and best practices for specific use cases.
+
+Teams building complex systems benefit from architectural advice to avoid common pitfalls and optimize their graph database implementation. Poor architectural decisions early in development create technical debt that becomes expensive to fix later.
+
+Architecture consultations provide recommendations on graph schema design, query optimization strategies, and integration patterns that match your application requirements.
diff --git a/cloud/free-tier.md b/cloud/free-tier.md
new file mode 100644
index 00000000..73a78428
--- /dev/null
+++ b/cloud/free-tier.md
@@ -0,0 +1,45 @@
+---
+title: "Free Tier"
+parent: "Cloud DBaaS"
+nav_order: 1
+description: "FalkorDB DBaaS Free Tier"
+---
+
+
+
+# Free Tier
+FalkorDB's free cloud tier gives you instant access to a graph database with multi-graph support and multi-tenancy capabilities. You can deploy on AWS or GCP with 100MB of storage and rely on community support to get started.
+
+The free tier provides everything you need to explore FalkorDB and build initial prototypes. When your application grows and requires TLS security, VPC networking, high availability, automated backups, or dedicated support, you can upgrade to a paid plan that includes these enterprise features.
+
+## FalkorDB Pricing Plans Comparison
+
+| Feature | FREE | STARTUP | PRO | ENTERPRISE |
+| :--- | :---: | :---: | :---: | :---: |
+| **Monthly Cost (from)** | **Free** | **$73** | **$350** | **Custom** |
+| Multi-Graph / Multi-Tenancy | **β** | **β** | **β** | **β** |
+| Graph Access Control | **β** | **β** | **β** | **β** |
+| TLS | β | **β** | **β** | **β** |
+| VPC | β | β | β | **β** |
+| Cluster Deployment | β | β | **β** | **β** |
+| High Availability | β | β | **β** | **β** |
+| Multi-zone Deployment | β | β | **β** | **β** |
+| Scalability | β | β | **β** | **β** |
+| Continuous Persistence | β | β | **β** | **β** |
+| Automated Backups | β | Every 12 Hours | Every 12 Hours | Every Hour |
+| Advanced Monitoring | β | β | β | **β** |
+| **Support** | Community | Community | 24/7 | Dedicated |
+| Dedicated Account Manager | β | β | β | **β** |
+| **Cloud Providers** | AWS, GCP | AWS, GCP | AWS, GCP | AWS, GCP, Azure |
+| **Call-to-Action** | [Sign up](https://app.falkordb.cloud/signup) | [Sign up](https://app.falkordb.cloud/signup) | [Sign up](https://app.falkordb.cloud/signup) | [Contact Us](mailto:info@falkordb.com) |
+
+#### Terms
+> β οΈ Free instances that aren't utilized for 1 day will be stopped, and deleted after 7 days.
+Need an extension? Speak to [sales](https://www.falkordb.com/get-a-demo/))
+
+## Getting Started
+
+[](https://www.youtube.com/watch?v=z0XO4pb2t5Y)
+
+βοΈ Spin up your first FalkorDB Cloud instance:
+[](https://app.falkordb.cloud/signup)
diff --git a/cloud/index.md b/cloud/index.md
new file mode 100644
index 00000000..b6f9ea00
--- /dev/null
+++ b/cloud/index.md
@@ -0,0 +1,62 @@
+---
+title: "Cloud DBaaS"
+description: Cloud Offering
+nav_order:
+has_children: true
+---
+
+
+
+# FalkorDB Cloud DBaaS
+
+Get started with FalkorDB's cloud offering. The platform provides several enterprise features, including multi-tenancy, across all tiers. Browse the available plans and select the one that suits your needs. You can scale and upgrade your deployment when ready.
+
+## Features & Services
+
+| Group | Features |
+| :--- | :--- |
+| **Availability & Resilience** | - High Availability
- Multi-zone Deployment
- Multi-Graph / Multi-Tenancy
- Automated Backups
- Continuous Persistence |
+| **Security & Access** | - Graph Access Control
- TLS
- VPC Peering |
+| **Deployment & Scaling** | - Dedicated Cluster Deployment
- Scalability |
+| **Support & Monitoring** | - Dedicated Support
- Advanced Monitoring
- Dedicated Account Manager |
+| βοΈ **Cloud Providers** | - AWS
- GCP
- Azure (BYOC) |
+
+[](https://github.com/FalkorDB/docs/edit/Cloud-Docs/cloud/features.md)
+
+---
+
+### Billing & Setup
+βΉοΈ Prior to subscribing to any of FalkorDB's paid cloud tiers, please set up your billing information here:
+> Adding your billing information is an easy, 2-step process:
+> 1. Create a billing account ([Link](https://app.falkordb.cloud/billing))
+> 2. Input your billing information
+
+
+
+## Free Tier
+
+The FalkorDB Free Tier provides a free FalkorDB instance for evaluation purposes. You can deploy, connect, and share the instance with minimal effort and no maintenance.
+
+[](https://github.com/FalkorDB/docs/cloud/free-tier.md)
+[](https://www.youtube.com/watch?v=z0XO4pb2t5Y)
+
+## Startup Tier
+
+The FalkorDB Startup Tier provides a production-ready standalone FalkorDB deployment. Pick your machine size, add a dataset size, and start extracting insights.
+
+[](https://github.com/FalkorDB/docs/cloud/startup-tier.md)
+[](https://www.youtube.com/watch?v=xjpLPoQgo2s)
+
+## Pro Tier
+
+The Pro Tier provides a robust, dedicated environment to scale your application, including highly-available setups.
+
+[](https://github.com/FalkorDB/docs/cloud/pro-tier.md)
+[](https://youtu.be/UIzrW9otvYM?si=P1too6QjZ5r9AHtB)
+
+## Enterprise
+
+The Enterprise Tier is fully optimized for mission-critical applications, providing the highest levels of security, availability, and dedicated operational support. Schedule a call with a FalkorDB solutions architect to learn more.
+
+[](https://github.com/FalkorDB/docs/cloud/enterprise-tier.md)
+[](https://youtu.be/fu_8CLFKYSs?si=G7K6dN1i5tyqXTfC)
diff --git a/cloud/pro-tier.md b/cloud/pro-tier.md
new file mode 100644
index 00000000..1d44f1aa
--- /dev/null
+++ b/cloud/pro-tier.md
@@ -0,0 +1,90 @@
+---
+title: "Pro Tier"
+parent: "Cloud DBaaS"
+nav_order: 3
+description: "FalkorDB DBaaS Pro Tier"
+---
+
+
+
+
+# Pro Tier
+FalkorDB's **Pro Tier** is your solution for high-performance, production-ready graph database workloads, starting at **$350/Month**. This tier is designed for applications requiring **High Availability (HA)**, **Multi-zone Deployment**, and robust **Scalability**. It includes essential infrastructure features like **Cluster Deployment** and **Continuous Persistence (AOF + Snapshot)**, backed by **24-hour Dedicated Support**.
+
+The Pro Tier provides a robust environment to scale your application with confidence. When your needs extend to features like VPC Peering, Advanced Monitoring, or a Dedicated Account Manager, you can easily upgrade to the Enterprise plan.
+
+## FalkorDB Pricing Plans Comparison
+
+| Feature | FREE | STARTUP | PRO | ENTERPRISE |
+| :--- | :---: | :---: | :---: | :---: |
+| **Monthly Cost (from)** | **Free** | **$73** | **$350** | **Custom** |
+| Multi-Graph / Multi-Tenancy | β | β | **π’** | β |
+| Graph Access Control | β | β | **π’** | β |
+| **TLS** | β | β | **π’** | β |
+| VPC | β | β | **π΄** | β |
+| Cluster Deployment | β | β | **π’** | β |
+| High Availability | β | β | **π’** | β |
+| Multi-zone Deployment | β | β | **π’** | β |
+| Scalability | β | β | **π’** | β |
+| Continuous Persistence | β | β | **π’** | β |
+| **Automated Backups** | β | Every 12 Hours | **Every 12 Hours** | Every Hour |
+| Advanced Monitoring | β | β | **π΄** | β |
+| **Support** | Community | Community | **24/7** | Dedicated |
+| Dedicated Account Manager | β | β | **π΄** | β |
+| **Cloud Providers** | AWS, GCP | AWS, GCP | **AWS, GCP** | AWS, GCP, Azure (BYOC) |
+| **Get started** | [Sign up](https://app.falkordb.cloud/signup) | [Sign up](https://app.falkordb.cloud/signup) | [Sign up](https://app.falkordb.cloud/signup) | [Contact Us](mailto:info@falkordb.com) |
+
+## Terms
+### Pricing Calculation
+> We charge deployments based on **Core/Hour** and **Memory GB/Hour** usage. You pay **$0.200 per Core/Hour** and **$0.01 per Memory GB/Hour**.
+
+## Standalone
+
+| Instance Type | Monthly Cost |
+| :--- | ---: |
+| E2-standard-2 / m6i.large (Starting Instance) | $350.40 |
+| E2-standard-4 / m6i.xlarge | $700.80 |
+| E2-custom-4-8192 / c6i.xlarge | $642.40 |
+| E2-custom-8-16384 / c6i.2xlarge | $1,284.80 |
+| E2-custom-16-32768 / c6i.4xlarge | $2,569.60 |
+| E2-custom-32-65536 / c6i.8xlarge | $5,139.20 |
+
+## Replicated (High Availability, Master (x1), Replica (x1))
+
+
+| Instances Type | Monthly Cost |
+| :-------------------------------------------- | -----------: |
+| E2-standard-2 / m6i.large (Starting Instance) | \$1,007.40 |
+| E2-standard-4 / m6i.xlarge | \$1,708.20 |
+| E2-custom-4-8192 / c6i.xlarge | \$1,591.40 |
+| E2-custom-8-16384 / c6i.2xlarge | \$2,876.20 |
+| E2-custom-16-32768 / c6i.4xlarge | \$5,445.80 |
+| E2-custom-32-65536 / c6i.8xlarge | \$10,585.00 |
+
+> Note: We charge an additional 2 cores and 2 GB for replication and cluster since they require an extra component (sentinel for replication and rebalancer for cluster).
+
+---
+
+
+> Use our **[graph size calculator](https://www.falkordb.com/graph-database-graph-size-calculator/)** to further estimate your cost.
+> β οΈ Prices are subject to change
+
+## Getting Started
+
+
+
+
+
+βοΈ Spin up your first FalkorDB Cloud instance:
+[](https://app.falkordb.cloud/signup)
diff --git a/cloud/startup-tier.md b/cloud/startup-tier.md
new file mode 100644
index 00000000..97ec4821
--- /dev/null
+++ b/cloud/startup-tier.md
@@ -0,0 +1,59 @@
+---
+title: "Startup Tier"
+parent: "Cloud DBaaS"
+nav_order: 2
+description: "FalkorDB DBaaS Startup Tier"
+---
+
+
+
+
+# Startup Tier
+FalkorDB's **Startup Tier** gives you instant access to a production-ready graph database starting at **$73/Month**. This tier is designed to help you **Build a Powerful MVP** with standalone deployment, multi-graph support, and multi-tenancy capabilities. You can deploy on AWS, GCP, or Azure (BYOC) and rely on community support to grow your application.
+
+The Startup Tier includes essential features like **TLS** and **Automated Backups (Every 12 Hours)**, making it a robust, secure choice for your first production workload. When your application requires High Availability, dedicated support, or advanced enterprise features like VPC networking, you can easily upgrade to a Pro or Enterprise plan.
+
+## FalkorDB Pricing Plans Comparison
+
+| Feature | FREE | STARTUP | PRO | ENTERPRISE |
+| :--- | :---: | :---: | :---: | :---: |
+| **Monthly Cost (from)** | **Free** | **$73** | **$350** | **Custom** |
+| Multi-Graph / Multi-Tenancy | β | **π’** | β | β |
+| Graph Access Control | β | **π’** | β | β |
+| **TLS** | β | **π’** | β | β |
+| VPC | β | **π΄** | β | β |
+| Cluster Deployment | β | **π΄** | β | β |
+| High Availability | β | **π΄** | β | β |
+| Multi-zone Deployment | β | **π΄** | β | β |
+| Scalability | β | **π΄** | β | β |
+| Continuous Persistence | β | **π΄** | β | β |
+| **Automated Backups** | β | **Every 12 Hours** | Every 12 Hours | Every Hour |
+| Advanced Monitoring | β | **π΄** | β | β |
+| **Support** | Community | **Community** | 24/7 | Dedicated |
+| Dedicated Account Manager | β | **π΄** | β | β |
+| **Cloud Providers** | AWS, GCP | **AWS, GCP** | AWS, GCP | AWS, GCP, Azure (BYOC) |
+| **Call-to-Action** | [Sign up](https://app.falkordb.cloud/signup) | [Sign up](https://app.falkordb.cloud/signup) | [Sign up](https://app.falkordb.cloud/signup) | [Contact Us](mailto:info@falkordb.com) |
+
+## Terms
+### Pricing Calculation
+> We calculate deployment costs based on **Memory GB/Hour** usage. Each Memory GB/Hour costs **$0.100**.
+>
+> The list below shows approximate monthly costs for different instance sizes (based on 730 hours/month):
+>
+> * **1 Gigabyte memory instance:** $0.100 Γ 1 (Memory GB) Γ 730 hours = **$73/month***
+> * **2 Gigabyte memory instance:** $0.100 Γ 2 (Memory GB) Γ 730 hours = **$146/month***
+>
+> You can estimate your monthly costs by multiplying your instance's memory allocation (in GB) by **$73**.
+>
+> Use our **[graph size calculator](https://www.falkordb.com/graph-database-graph-size-calculator/)** to further estimate your cost.
+>
+> β οΈ Prices are subject to change
+
+## Getting Started
+
+
+
+
+
+βοΈ Spin up your first FalkorDB Cloud instance:
+[](https://app.falkordb.cloud/signup)
diff --git a/commands/graph.delete.md b/commands/graph.delete.md
index 278a2ed9..1e3a7a18 100644
--- a/commands/graph.delete.md
+++ b/commands/graph.delete.md
@@ -8,11 +8,20 @@ parent: "Commands"
# GRAPH.DELETE
-Completely removes the graph and all of its entities.
+Completely removes a graph and all of its entities (nodes and relationships).
-Arguments: `Graph name`
+## Syntax
-Returns: `String indicating if operation succeeded or failed.`
+```
+GRAPH.DELETE graph_name
+```
+
+**Arguments:**
+- `graph_name` - Name of the graph to delete
+
+**Returns:** String indicating if the operation succeeded or failed.
+
+## Examples
{% capture shell_0 %}
GRAPH.DELETE us_government
@@ -36,7 +45,9 @@ graph.delete()?;
{% include code_tabs.html id="tabs_0" shell=shell_0 python=python_0 javascript=javascript_0 java=java_0 rust=rust_0 %}
-Note: To delete a node from the graph (not the entire graph), execute a `MATCH` query and pass the alias to the `DELETE` clause:
+## Deleting Individual Nodes
+
+**Note:** To delete specific nodes or relationships (not the entire graph), use the Cypher `DELETE` clause with a `MATCH` query:
{% capture shell_1 %}
GRAPH.QUERY DEMO_GRAPH "MATCH (x:Y {propname: propvalue}) DELETE x"
@@ -60,5 +71,5 @@ graph.query("MATCH (x:Y {propname: propvalue}) DELETE x")?;
{% include code_tabs.html id="tabs_1" shell=shell_1 python=python_1 javascript=javascript_1 java=java_1 rust=rust_1 %}
-WARNING: When you delete a node, all of the node's incoming/outgoing relationships are also removed.
+**β οΈ Warning:** When you delete a node using the Cypher `DELETE` clause, all of the node's incoming and outgoing relationships are also automatically removed.
diff --git a/commands/graph.info.md b/commands/graph.info.md
index 46972591..d34327b1 100644
--- a/commands/graph.info.md
+++ b/commands/graph.info.md
@@ -7,7 +7,17 @@ parent: "Commands"
# GRAPH.INFO
-Returns information and statistics about the current executing commands.
+Returns information and statistics about currently running and waiting queries.
+
+## Syntax
+
+```
+GRAPH.INFO [RunningQueries | WaitingQueries]
+```
+
+If no argument is provided, both running and waiting queries are returned.
+
+## Examples
```sh
127.0.0.1:6379> GRAPH.INFO
diff --git a/commands/graph.list.md b/commands/graph.list.md
index ffa20d36..53ed7812 100644
--- a/commands/graph.list.md
+++ b/commands/graph.list.md
@@ -10,6 +10,54 @@ parent: "Commands"
Lists all graph keys in the keyspace.
+## Examples
+
+{% capture shell_0 %}
+GRAPH.LIST
+{% endcapture %}
+
+{% capture python_0 %}
+from falkordb import FalkorDB
+db = FalkorDB(host='localhost', port=6379)
+graphs = db.list_graphs()
+print(graphs)
+{% endcapture %}
+
+{% capture javascript_0 %}
+import { FalkorDB } from 'falkordb';
+const db = await FalkorDB.connect({
+ socket: { host: 'localhost', port: 6379 }
+});
+const graphs = await db.list();
+console.log(graphs);
+{% endcapture %}
+
+{% capture java_0 %}
+import com.falkordb.*;
+
+Driver driver = FalkorDB.driver("localhost", 6379);
+List graphs = driver.listGraphs();
+System.out.println(graphs);
+{% endcapture %}
+
+{% capture rust_0 %}
+use falkordb::{FalkorClientBuilder, FalkorConnectionInfo};
+
+let connection_info: FalkorConnectionInfo = "falkor://127.0.0.1:6379"
+ .try_into()
+ .expect("Invalid connection info");
+let client = FalkorClientBuilder::new()
+ .with_connection_info(connection_info)
+ .build()
+ .expect("Failed to build client");
+let graphs = client.list_graphs();
+println!("{:?}", graphs);
+{% endcapture %}
+
+{% include code_tabs.html id="list_tabs" shell=shell_0 python=python_0 javascript=javascript_0 java=java_0 rust=rust_0 %}
+
+### Sample Output
+
```sh
127.0.0.1:6379> GRAPH.LIST
2) G
diff --git a/commands/graph.memory.md b/commands/graph.memory.md
index 4555078b..75338383 100644
--- a/commands/graph.memory.md
+++ b/commands/graph.memory.md
@@ -46,16 +46,38 @@ The command returns an array of key-value pairs, where each pair represents a sp
## Examples
### Basic Usage
-```bash
+
+{% capture shell_0 %}
GRAPH.MEMORY USAGE myGraph
-```
+{% endcapture %}
+
+{% capture javascript_0 %}
+import { FalkorDB } from 'falkordb';
+const db = await FalkorDB.connect({
+ socket: { host: 'localhost', port: 6379 }
+});
+const graph = db.selectGraph('myGraph');
+const memoryInfo = await graph.memoryUsage();
+console.log(memoryInfo);
+{% endcapture %}
+
+{% include code_tabs.html id="memory_basic_tabs" shell=shell_0 javascript=javascript_0 %}
### With Sampling
-```bash
+
+{% capture shell_1 %}
GRAPH.MEMORY USAGE myGraph SAMPLES 500
-```
+{% endcapture %}
+
+{% capture javascript_1 %}
+const memoryInfo = await graph.memoryUsage({ samples: 500 });
+console.log(memoryInfo);
+{% endcapture %}
+
+{% include code_tabs.html id="memory_samples_tabs" shell=shell_1 javascript=javascript_1 %}
### Sample Output
+
```sh
127.0.0.1:6379> GRAPH.MEMORY USAGE flights
1) "total_graph_sz_mb"
diff --git a/commands/graph.ro-query.md b/commands/graph.ro-query.md
index 715ad5d4..7caf1a17 100644
--- a/commands/graph.ro-query.md
+++ b/commands/graph.ro-query.md
@@ -25,6 +25,21 @@ GRAPH.RO_QUERY us_government "MATCH (p:president)-[:born]->(:state {name:'Hawaii
graph.ro_query("MATCH (p:president)-[:born]->(:state {name:'Hawaii'}) RETURN p")
{% endcapture %}
-{% include code_tabs.html id="tabs_0" shell=shell_0 python=python_0 %}
+{% capture javascript_0 %}
+const result = await graph.ro_query("MATCH (p:president)-[:born]->(:state {name:'Hawaii'}) RETURN p");
+console.log(result);
+{% endcapture %}
+
+{% capture java_0 %}
+ResultSet result = graph.readOnlyQuery("MATCH (p:president)-[:born]->(:state {name:'Hawaii'}) RETURN p");
+System.out.println(result);
+{% endcapture %}
+
+{% capture rust_0 %}
+let result = graph.ro_query(r#"MATCH (p:president)-[:born]->(:state {name:'Hawaii'}) RETURN p"#).execute().await?;
+println!("{:?}", result);
+{% endcapture %}
+
+{% include code_tabs.html id="tabs_0" shell=shell_0 python=python_0 javascript=javascript_0 java=java_0 rust=rust_0 %}
Query-level timeouts can be set as described in [the configuration section](/configuration#timeout).
diff --git a/commands/graph.slowlog.md b/commands/graph.slowlog.md
index 4e35c988..28040bfc 100644
--- a/commands/graph.slowlog.md
+++ b/commands/graph.slowlog.md
@@ -16,6 +16,36 @@ Each item in the list has the following structure:
3. The issued query.
4. The amount of time needed for its execution, in milliseconds.
+## Examples
+
+### Get slowlog
+
+{% capture shell_0 %}
+GRAPH.SLOWLOG graph_id
+{% endcapture %}
+
+{% capture python_0 %}
+from falkordb import FalkorDB
+db = FalkorDB(host='localhost', port=6379)
+graph = db.select_graph('graph_id')
+slowlog = graph.slowlog()
+print(slowlog)
+{% endcapture %}
+
+{% capture javascript_0 %}
+import { FalkorDB } from 'falkordb';
+const db = await FalkorDB.connect({
+ socket: { host: 'localhost', port: 6379 }
+});
+const graph = db.selectGraph('graph_id');
+const slowlog = await graph.slowLog();
+console.log(slowlog);
+{% endcapture %}
+
+{% include code_tabs.html id="slowlog_tabs" shell=shell_0 python=python_0 javascript=javascript_0 %}
+
+### Sample Output
+
```sh
GRAPH.SLOWLOG graph_id
1) 1) "1581932396"
@@ -28,10 +58,16 @@ GRAPH.SLOWLOG graph_id
4) "0.288"
```
-To reset a graph's slowlog issue the following command:
+### Reset slowlog
-```sh
+{% capture shell_1 %}
GRAPH.SLOWLOG graph_id RESET
-```
+{% endcapture %}
+
+{% capture python_1 %}
+graph.slowlog_reset()
+{% endcapture %}
+
+{% include code_tabs.html id="slowlog_reset_tabs" shell=shell_1 python=python_1 %}
Once cleared the information is lost forever.
diff --git a/cypher/create.md b/cypher/create.md
index 87bb307e..8870c93a 100644
--- a/cypher/create.md
+++ b/cypher/create.md
@@ -8,25 +8,31 @@ parent: "Cypher Language"
# CREATE
-CREATE is used to introduce new nodes and relationships.
+The `CREATE` clause is used to introduce new nodes and relationships into the graph.
-The simplest example of CREATE would be a single node creation:
+## Creating Nodes
+
+The simplest example creates a single node without any labels or properties:
```sh
CREATE (n)
```
-It's possible to create multiple entities by separating them with a comma.
+You can create multiple entities by separating them with commas:
```sh
CREATE (n),(m)
```
+Create a node with a label and properties:
+
```sh
CREATE (:Person {name: 'Kurt', age: 27})
```
-To add relations between nodes, in the following example we first find an existing source node. After it's found, we create a new relationship and destination node.
+## Creating Relationships
+
+To add relationships between nodes, you typically match existing nodes first, then create the relationship. In this example, we find an existing source node and create a new relationship with a new destination node:
```sh
GRAPH.QUERY DEMO_GRAPH
@@ -35,17 +41,17 @@ WHERE a.name = 'Kurt'
CREATE (a)-[:MEMBER]->(:Band {name:'Nirvana'})"
```
-Here the source node is a bounded node, while the destination node is unbounded.
+Here the source node `(a:Person)` is matched (bound), while the destination node `(:Band)` is unbound and will be created.
-As a result, a new node is created representing the band Nirvana and a new relation connects Kurt to the band.
+This query creates a new node representing the band Nirvana and a new `MEMBER` relationship connecting Kurt to the band.
-Lastly we create a complete pattern.
+## Creating Complete Patterns
-All entities within the pattern which are not bounded will be created.
+You can create entire graph patterns in a single statement. All entities within the pattern that are not bound (matched) will be created:
```sh
GRAPH.QUERY DEMO_GRAPH
"CREATE (jim:Person{name:'Jim', age:29})-[:FRIENDS]->(pam:Person {name:'Pam', age:27})-[:WORKS]->(:Employer {name:'Dunder Mifflin'})"
```
-This query will create three nodes and two relationships.
+This query creates three nodes (Jim, Pam, and an Employer) and two relationships (FRIENDS and WORKS), establishing a complete graph pattern in one operation.
diff --git a/cypher/delete.md b/cypher/delete.md
index 85cd77b9..5cf46aa7 100644
--- a/cypher/delete.md
+++ b/cypher/delete.md
@@ -8,9 +8,13 @@ parent: "Cypher Language"
# DELETE
-DELETE is used to remove both nodes and relationships.
+The `DELETE` clause is used to remove nodes and relationships from the graph.
-Note that deleting a node also deletes all of its incoming and outgoing relationships.
+## Important Behavior
+
+**β οΈ Note:** Deleting a node automatically deletes all of its incoming and outgoing relationships. You cannot have orphaned relationships in the graph.
+
+## Deleting Nodes
To delete a node and all of its relationships:
@@ -18,10 +22,30 @@ To delete a node and all of its relationships:
GRAPH.QUERY DEMO_GRAPH "MATCH (p:Person {name:'Jim'}) DELETE p"
```
-To delete relationship:
+## Deleting Relationships
+
+To delete specific relationships:
```sh
GRAPH.QUERY DEMO_GRAPH "MATCH (:Person {name:'Jim'})-[r:FRIENDS]->() DELETE r"
```
-This query will delete all `friend` outgoing relationships from the node with the name 'Jim'.
\ No newline at end of file
+This query deletes all outgoing `FRIENDS` relationships from the node with name 'Jim', while keeping the nodes intact.
+
+## Common Patterns
+
+### Delete all nodes and relationships in a graph
+
+```sh
+GRAPH.QUERY DEMO_GRAPH "MATCH (n) DETACH DELETE n"
+```
+
+The `DETACH DELETE` automatically removes all relationships before deleting the node.
+
+### Conditional deletion
+
+```sh
+GRAPH.QUERY DEMO_GRAPH "MATCH (p:Person) WHERE p.age < 18 DELETE p"
+```
+
+Deletes all Person nodes where age is less than 18.
\ No newline at end of file
diff --git a/cypher/index.md b/cypher/index.md
index 2d24d32e..b4a70e40 100644
--- a/cypher/index.md
+++ b/cypher/index.md
@@ -42,4 +42,4 @@ See the list of available graph [algorithms](/algorithms).
## Indexing
-See how to use [indexing](/cypher/indexing).
+See how to use [indexing](/cypher/indexing/).
diff --git a/cypher/indexing.md b/cypher/indexing.md
deleted file mode 100644
index d6b97939..00000000
--- a/cypher/indexing.md
+++ /dev/null
@@ -1,863 +0,0 @@
----
-title: "Indexing"
-nav_order: 21
-description: >
- FalkorDB supports single-property indexes for node labels and for relationship type. String, numeric, and geospatial data types can be indexed.
-parent: "Cypher Language"
----
-
-# Indexing
-
-## Range Index
-
-FalkorDB supports single-property indexes for node labels and for relationship type. String, numeric, and geospatial data types can be indexed.
-
-### Creating an index for a node label
-
-For a node label, the index creation syntax is:
-
-{% capture shell_0 %}
-GRAPH.QUERY DEMO_GRAPH "CREATE INDEX FOR (p:Person) ON (p.age)"
-{% endcapture %}
-
-{% capture python_0 %}
-graph.query("CREATE INDEX FOR (p:Person) ON (p.age)")
-{% endcapture %}
-
-{% capture javascript_0 %}
-await graph.query("CREATE INDEX FOR (p:Person) ON (p.age)");
-{% endcapture %}
-
-{% capture java_0 %}
-graph.query("CREATE INDEX FOR (p:Person) ON (p.age)");
-{% endcapture %}
-
-{% capture rust_0 %}
-graph.query("CREATE INDEX FOR (p:Person) ON (p.age)").execute().await?;
-{% endcapture %}
-
-{% include code_tabs.html id="create_index_tabs" shell=shell_0 python=python_0 javascript=javascript_0 java=java_0 rust=rust_0 %}
-
-An old syntax is also supported:
-
-{% capture shell_1 %}
-GRAPH.QUERY DEMO_GRAPH "CREATE INDEX ON :Person(age)"
-{% endcapture %}
-
-{% capture python_1 %}
-graph.query("CREATE INDEX ON :Person(age)")
-{% endcapture %}
-
-{% capture javascript_1 %}
-await graph.query("CREATE INDEX ON :Person(age)");
-{% endcapture %}
-
-{% capture java_1 %}
-graph.query("CREATE INDEX ON :Person(age)");
-{% endcapture %}
-
-{% capture rust_1 %}
-graph.query("CREATE INDEX ON :Person(age)").execute().await?;
-{% endcapture %}
-
-{% include code_tabs.html id="old_syntax_tabs" shell=shell_1 python=python_1 javascript=javascript_1 java=java_1 rust=rust_1 %}
-
-After an index is explicitly created, it will automatically be used by queries that reference that label and any indexed property in a filter.
-
-{% capture shell_2 %}
-GRAPH.EXPLAIN DEMO_GRAPH "MATCH (p:Person) WHERE p.age > 80 RETURN p"
-1) "Results"
-2) " Project"
-3) " Index Scan | (p:Person)"
-{% endcapture %}
-
-{% capture python_2 %}
-result = graph.explain("MATCH (p:Person) WHERE p.age > 80 RETURN p")
-print(result)
-# Output:
-# Results
-# Project
-# Index Scan | (p:Person)
-{% endcapture %}
-
-{% capture javascript_2 %}
-const result = await graph.explain("MATCH (p:Person) WHERE p.age > 80 RETURN p");
-console.log(result);
-// Output:
-// Results
-// Project
-// Index Scan | (p:Person)
-{% endcapture %}
-
-{% capture java_2 %}
-String result = graph.explain("MATCH (p:Person) WHERE p.age > 80 RETURN p");
-System.out.println(result);
-// Output:
-// Results
-// Project
-// Index Scan | (p:Person)
-{% endcapture %}
-
-{% capture rust_2 %}
-let result = graph.explain("MATCH (p:Person) WHERE p.age > 80 RETURN p").execute().await?;
-println!("{}", result);
-// Output:
-// Results
-// Project
-// Index Scan | (p:Person)
-{% endcapture %}
-
-{% include code_tabs.html id="explain_tabs" shell=shell_2 python=python_2 javascript=javascript_2 java=java_2 rust=rust_2 %}
-
-This can significantly improve the runtime of queries with very specific filters. An index on `:employer(name)`, for example, will dramatically benefit the query:
-
-{% capture shell_3 %}
-GRAPH.QUERY DEMO_GRAPH
-"MATCH (:Employer {name: 'Dunder Mifflin'})-[:EMPLOYS]->(p:Person) RETURN p"
-{% endcapture %}
-
-{% capture python_3 %}
-result = graph.query("MATCH (:Employer {name: 'Dunder Mifflin'})-[:EMPLOYS]->(p:Person) RETURN p")
-{% endcapture %}
-
-{% capture javascript_3 %}
-const result = await graph.query("MATCH (:Employer {name: 'Dunder Mifflin'})-[:EMPLOYS]->(p:Person) RETURN p");
-{% endcapture %}
-
-{% capture java_3 %}
-ResultSet result = graph.query("MATCH (:Employer {name: 'Dunder Mifflin'})-[:EMPLOYS]->(p:Person) RETURN p");
-{% endcapture %}
-
-{% capture rust_3 %}
-let result = graph.query("MATCH (:Employer {name: 'Dunder Mifflin'})-[:EMPLOYS]->(p:Person) RETURN p").execute().await?;
-{% endcapture %}
-
-{% include code_tabs.html id="employer_query_tabs" shell=shell_3 python=python_3 javascript=javascript_3 java=java_3 rust=rust_3 %}
-
-An example of utilizing a geospatial index to find `Employer` nodes within 5 kilometers of Scranton are:
-
-{% capture shell_4 %}
-GRAPH.QUERY DEMO_GRAPH
-"WITH point({latitude:41.4045886, longitude:-75.6969532}) AS scranton MATCH (e:Employer) WHERE distance(e.location, scranton) < 5000 RETURN e"
-{% endcapture %}
-
-{% capture python_4 %}
-result = graph.query("WITH point({latitude:41.4045886, longitude:-75.6969532}) AS scranton MATCH (e:Employer) WHERE distance(e.location, scranton) < 5000 RETURN e")
-{% endcapture %}
-
-{% capture javascript_4 %}
-const result = await graph.query("WITH point({latitude:41.4045886, longitude:-75.6969532}) AS scranton MATCH (e:Employer) WHERE distance(e.location, scranton) < 5000 RETURN e");
-{% endcapture %}
-
-{% capture java_4 %}
-ResultSet result = graph.query("WITH point({latitude:41.4045886, longitude:-75.6969532}) AS scranton MATCH (e:Employer) WHERE distance(e.location, scranton) < 5000 RETURN e");
-{% endcapture %}
-
-{% capture rust_4 %}
-let result = graph.query("WITH point({latitude:41.4045886, longitude:-75.6969532}) AS scranton MATCH (e:Employer) WHERE distance(e.location, scranton) < 5000 RETURN e").execute().await?;
-{% endcapture %}
-
-{% include code_tabs.html id="geospatial_tabs" shell=shell_4 python=python_4 javascript=javascript_4 java=java_4 rust=rust_4 %}
-
-Geospatial indexes can currently only be leveraged with `<` and `<=` filters; matching nodes outside of the given radius is performed using conventional matching.
-
-### Creating an index for a relationship type
-
-For a relationship type, the index creation syntax is:
-
-{% capture shell_5 %}
-GRAPH.QUERY DEMO_GRAPH "CREATE INDEX FOR ()-[f:FOLLOW]-() ON (f.created_at)"
-{% endcapture %}
-
-{% capture python_5 %}
-graph.query("CREATE INDEX FOR ()-[f:FOLLOW]-() ON (f.created_at)")
-{% endcapture %}
-
-{% capture javascript_5 %}
-await graph.query("CREATE INDEX FOR ()-[f:FOLLOW]-() ON (f.created_at)");
-{% endcapture %}
-
-{% capture java_5 %}
-graph.query("CREATE INDEX FOR ()-[f:FOLLOW]-() ON (f.created_at)");
-{% endcapture %}
-
-{% capture rust_5 %}
-graph.query("CREATE INDEX FOR ()-[f:FOLLOW]-() ON (f.created_at)").execute().await?;
-{% endcapture %}
-
-{% include code_tabs.html id="relationship_index_tabs" shell=shell_5 python=python_5 javascript=javascript_5 java=java_5 rust=rust_5 %}
-
-Then the execution plan for using the index:
-
-{% capture shell_6 %}
-GRAPH.EXPLAIN DEMO_GRAPH "MATCH (p:Person {id: 0})-[f:FOLLOW]->(fp) WHERE 0 < f.created_at AND f.created_at < 1000 RETURN fp"
-1) "Results"
-2) " Project"
-3) " Edge By Index Scan | [f:FOLLOW]"
-4) " Node By Index Scan | (p:Person)"
-{% endcapture %}
-
-{% capture python_6 %}
-result = graph.explain("MATCH (p:Person {id: 0})-[f:FOLLOW]->(fp) WHERE 0 < f.created_at AND f.created_at < 1000 RETURN fp")
-print(result)
-# Output:
-# Results
-# Project
-# Edge By Index Scan | [f:FOLLOW]
-# Node By Index Scan | (p:Person)
-{% endcapture %}
-
-{% capture javascript_6 %}
-const result = await graph.explain("MATCH (p:Person {id: 0})-[f:FOLLOW]->(fp) WHERE 0 < f.created_at AND f.created_at < 1000 RETURN fp");
-console.log(result);
-// Output:
-// Results
-// Project
-// Edge By Index Scan | [f:FOLLOW]
-// Node By Index Scan | (p:Person)
-{% endcapture %}
-
-{% capture java_6 %}
-String result = graph.explain("MATCH (p:Person {id: 0})-[f:FOLLOW]->(fp) WHERE 0 < f.created_at AND f.created_at < 1000 RETURN fp");
-System.out.println(result);
-// Output:
-// Results
-// Project
-// Edge By Index Scan | [f:FOLLOW]
-// Node By Index Scan | (p:Person)
-{% endcapture %}
-
-{% capture rust_6 %}
-let result = graph.explain("MATCH (p:Person {id: 0})-[f:FOLLOW]->(fp) WHERE 0 < f.created_at AND f.created_at < 1000 RETURN fp").execute().await?;
-println!("{}", result);
-// Output:
-// Results
-// Project
-// Edge By Index Scan | [f:FOLLOW]
-// Node By Index Scan | (p:Person)
-{% endcapture %}
-
-{% include code_tabs.html id="relationship_explain_tabs" shell=shell_6 python=python_6 javascript=javascript_6 java=java_6 rust=rust_6 %}
-
-This can significantly improve the runtime of queries that traverse super nodes or when we want to start traverse from relationships.
-
-### Deleting an index for a node label
-
-For a node label, the index deletion syntax is:
-
-{% capture shell_7 %}
-GRAPH.QUERY DEMO_GRAPH "DROP INDEX ON :Person(age)"
-{% endcapture %}
-
-{% capture python_7 %}
-graph.query("DROP INDEX ON :Person(age)")
-{% endcapture %}
-
-{% capture javascript_7 %}
-await graph.query("DROP INDEX ON :Person(age)");
-{% endcapture %}
-
-{% capture java_7 %}
-graph.query("DROP INDEX ON :Person(age)");
-{% endcapture %}
-
-{% capture rust_7 %}
-graph.query("DROP INDEX ON :Person(age)").execute().await?;
-{% endcapture %}
-
-{% include code_tabs.html id="drop_node_index_tabs" shell=shell_7 python=python_7 javascript=javascript_7 java=java_7 rust=rust_7 %}
-
-### Deleting an index for a relationship type
-
-For a relationship type, the index deletion syntax is:
-
-{% capture shell_8 %}
-GRAPH.QUERY DEMO_GRAPH "DROP INDEX ON :FOLLOW(created_at)"
-{% endcapture %}
-
-{% capture python_8 %}
-graph.query("DROP INDEX ON :FOLLOW(created_at)")
-{% endcapture %}
-
-{% capture javascript_8 %}
-await graph.query("DROP INDEX ON :FOLLOW(created_at)");
-{% endcapture %}
-
-{% capture java_8 %}
-graph.query("DROP INDEX ON :FOLLOW(created_at)");
-{% endcapture %}
-
-{% capture rust_8 %}
-graph.query("DROP INDEX ON :FOLLOW(created_at)").execute().await?;
-{% endcapture %}
-
-{% include code_tabs.html id="drop_relationship_index_tabs" shell=shell_8 python=python_8 javascript=javascript_8 java=java_8 rust=rust_8 %}
-
-### Array Indices
-
-FalkorDB supports indexing on array properties containing scalar values (e.g., integers, floats, strings), enabling efficient lookups for elements within such arrays.
-
-Note: Complex types like nested arrays, maps, or vectors are not supported for indexing.
-
-The following example demonstrates how to index and search an array property:
-
-{% capture shell_9 %}
-# Create a node with an array property
-GRAPH.QUERY DEMO_GRAPH "CREATE (:Person {samples: [-21, 30.5, 0, 90, 3.14]})"
-
-# Create an index on the array property
-GRAPH.QUERY DEMO_GRAPH "CREATE INDEX FOR (p:Person) ON (p.samples)"
-
-# Use the index to search for nodes containing a specific value in the array
-GRAPH.QUERY DEMO_GRAPH "MATCH (p:Person) WHERE 90 IN p.samples RETURN p"
-{% endcapture %}
-
-{% capture python_9 %}
-# Create a node with an array property
-graph.query("CREATE (:Person {samples: [-21, 30.5, 0, 90, 3.14]})")
-
-# Create an index on the array property
-graph.query("CREATE INDEX FOR (p:Person) ON (p.samples)")
-
-# Use the index to search for nodes containing a specific value in the array
-result = graph.query("MATCH (p:Person) WHERE 90 IN p.samples RETURN p")
-{% endcapture %}
-
-{% capture javascript_9 %}
-// Create a node with an array property
-await graph.query("CREATE (:Person {samples: [-21, 30.5, 0, 90, 3.14]})");
-
-// Create an index on the array property
-await graph.query("CREATE INDEX FOR (p:Person) ON (p.samples)");
-
-// Use the index to search for nodes containing a specific value in the array
-const result = await graph.query("MATCH (p:Person) WHERE 90 IN p.samples RETURN p");
-{% endcapture %}
-
-{% capture java_9 %}
-// Create a node with an array property
-graph.query("CREATE (:Person {samples: [-21, 30.5, 0, 90, 3.14]})");
-
-// Create an index on the array property
-graph.query("CREATE INDEX FOR (p:Person) ON (p.samples)");
-
-// Use the index to search for nodes containing a specific value in the array
-ResultSet result = graph.query("MATCH (p:Person) WHERE 90 IN p.samples RETURN p");
-{% endcapture %}
-
-{% capture rust_9 %}
-// Create a node with an array property
-graph.query("CREATE (:Person {samples: [-21, 30.5, 0, 90, 3.14]})").execute().await?;
-
-// Create an index on the array property
-graph.query("CREATE INDEX FOR (p:Person) ON (p.samples)").execute().await?;
-
-// Use the index to search for nodes containing a specific value in the array
-let result = graph.query("MATCH (p:Person) WHERE 90 IN p.samples RETURN p").execute().await?;
-{% endcapture %}
-
-{% include code_tabs.html id="array_index_tabs" shell=shell_9 python=python_9 javascript=javascript_9 java=java_9 rust=rust_9 %}
-
-## Full-text indexing
-
-FalkorDB leverages the indexing capabilities of [RediSearch](https://redis.io/docs/interact/search-and-query/) to provide full-text indices through procedure calls.
-
-## Creating a full-text index for a node label
-
-To construct a full-text index on the `title` property of all nodes with label `Movie`, use the syntax:
-
-{% capture shell_10 %}
-GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.createNodeIndex('Movie', 'title')"
-{% endcapture %}
-
-{% capture python_10 %}
-graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', 'title')")
-{% endcapture %}
-
-{% capture javascript_10 %}
-await graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', 'title')");
-{% endcapture %}
-
-{% capture java_10 %}
-graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', 'title')");
-{% endcapture %}
-
-{% capture rust_10 %}
-graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', 'title')").execute().await?;
-{% endcapture %}
-
-{% include code_tabs.html id="fulltext_create_tabs" shell=shell_10 python=python_10 javascript=javascript_10 java=java_10 rust=rust_10 %}
-
-More properties can be added to this index by adding their names to the above set of arguments, or using this syntax again with the additional names.
-
-{% capture shell_11 %}
-GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.createNodeIndex('Person', 'firstName', 'lastName')"
-{% endcapture %}
-
-{% capture python_11 %}
-graph.query("CALL db.idx.fulltext.createNodeIndex('Person', 'firstName', 'lastName')")
-{% endcapture %}
-
-{% capture javascript_11 %}
-await graph.query("CALL db.idx.fulltext.createNodeIndex('Person', 'firstName', 'lastName')");
-{% endcapture %}
-
-{% capture java_11 %}
-graph.query("CALL db.idx.fulltext.createNodeIndex('Person', 'firstName', 'lastName')");
-{% endcapture %}
-
-{% capture rust_11 %}
-graph.query("CALL db.idx.fulltext.createNodeIndex('Person', 'firstName', 'lastName')").execute().await?;
-{% endcapture %}
-
-{% include code_tabs.html id="fulltext_multi_property_tabs" shell=shell_11 python=python_11 javascript=javascript_11 java=java_11 rust=rust_11 %}
-
-RediSearch provide 2 index configuration options:
-
-1. Language - Define which language to use for stemming text, which is adding the base form of a word to the index. This allows the query for "going" to also return results for "go" and "gone", for example.
-2. Stopwords - These are words that are usually so common that they do not add much information to search, but take up a lot of space and CPU time in the index.
-
-To construct a full-text index on the `title` property using `German` language and using custom stopwords of all nodes with label `Movie`, use the syntax:
-
-{% capture shell_12 %}
-GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.createNodeIndex({ label: 'Movie', language: 'German', stopwords: ['a', 'ab'] }, 'title')"
-{% endcapture %}
-
-{% capture python_12 %}
-graph.query("CALL db.idx.fulltext.createNodeIndex({ label: 'Movie', language: 'German', stopwords: ['a', 'ab'] }, 'title')")
-{% endcapture %}
-
-{% capture javascript_12 %}
-await graph.query("CALL db.idx.fulltext.createNodeIndex({ label: 'Movie', language: 'German', stopwords: ['a', 'ab'] }, 'title')");
-{% endcapture %}
-
-{% capture java_12 %}
-graph.query("CALL db.idx.fulltext.createNodeIndex({ label: 'Movie', language: 'German', stopwords: ['a', 'ab'] }, 'title')");
-{% endcapture %}
-
-{% capture rust_12 %}
-graph.query("CALL db.idx.fulltext.createNodeIndex({ label: 'Movie', language: 'German', stopwords: ['a', 'ab'] }, 'title')").execute().await?;
-{% endcapture %}
-
-{% include code_tabs.html id="fulltext_config_tabs" shell=shell_12 python=python_12 javascript=javascript_12 java=java_12 rust=rust_12 %}
-
-RediSearch provide 3 additional field configuration options:
-
-1. Weight - The importance of the text in the field
-2. Nostem - Skip stemming when indexing text
-3. Phonetic - Enable phonetic search on the text
-
-To construct a full-text index on the `title` property with phonetic search of all nodes with label `Movie`, use the syntax:
-
-{% capture shell_13 %}
-GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.createNodeIndex('Movie', {field: 'title', phonetic: 'dm:en'})"
-{% endcapture %}
-
-{% capture python_13 %}
-graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', {field: 'title', phonetic: 'dm:en'})")
-{% endcapture %}
-
-{% capture javascript_13 %}
-await graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', {field: 'title', phonetic: 'dm:en'})");
-{% endcapture %}
-
-{% capture java_13 %}
-graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', {field: 'title', phonetic: 'dm:en'})");
-{% endcapture %}
-
-{% capture rust_13 %}
-graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', {field: 'title', phonetic: 'dm:en'})").execute().await?;
-{% endcapture %}
-
-{% include code_tabs.html id="fulltext_phonetic_tabs" shell=shell_13 python=python_13 javascript=javascript_13 java=java_13 rust=rust_13 %}
-
-## Utilizing a full-text index for a node label
-
-An index can be invoked to match any whole words contained within:
-
-{% capture shell_14 %}
-GRAPH.QUERY DEMO_GRAPH
-"CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node.title"
-1) 1) "node.title"
-2) 1) 1) "The Jungle Book"
- 2) 1) "The Book of Life"
-3) 1) "Query internal execution time: 0.927409 milliseconds"
-{% endcapture %}
-
-{% capture python_14 %}
-result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node.title")
-for record in result:
- print(record["node.title"])
-# Output:
-# The Jungle Book
-# The Book of Life
-{% endcapture %}
-
-{% capture javascript_14 %}
-const result = await graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node.title");
-for (const record of result.data) {
- console.log(record["node.title"]);
-}
-// Output:
-// The Jungle Book
-// The Book of Life
-{% endcapture %}
-
-{% capture java_14 %}
-ResultSet result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node.title");
-for (Record record : result) {
- System.out.println(record.get("node.title"));
-}
-// Output:
-// The Jungle Book
-// The Book of Life
-{% endcapture %}
-
-{% capture rust_14 %}
-let result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node.title").execute().await?;
-for record in result.data() {
- println!("{}", record["node.title"]);
-}
-// Output:
-// The Jungle Book
-// The Book of Life
-{% endcapture %}
-
-{% include code_tabs.html id="fulltext_query_tabs" shell=shell_14 python=python_14 javascript=javascript_14 java=java_14 rust=rust_14 %}
-
-This CALL clause can be interleaved with other Cypher clauses to perform more elaborate manipulations:
-
-```sh
-GRAPH.QUERY DEMO_GRAPH
-"CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node AS m
-WHERE m.genre = 'Adventure'
-RETURN m ORDER BY m.rating"
-1) 1) "m"
-2) 1) 1) 1) 1) "id"
- 2) (integer) 1168
- 2) 1) "labels"
- 2) 1) "Movie"
- 3) 1) "properties"
- 2) 1) 1) "genre"
- 2) "Adventure"
- 2) 1) "rating"
- 2) "7.6"
- 3) 1) "votes"
- 2) (integer) 151342
- 4) 1) "year"
- 2) (integer) 2016
- 5) 1) "title"
- 2) "The Jungle Book"
-3) 1) "Query internal execution time: 0.226914 milliseconds"
-```
-
-In addition to yielding matching nodes, full-text index scans will return the score of each node. This is the [TF-IDF](https://redis.io/docs/interact/search-and-query/advanced-concepts/scoring/#tfidf-default) score of the node, which is informed by how many times the search terms appear in the node and how closely grouped they are. This can be observed in the example:
-
-```sh
-GRAPH.QUERY DEMO_GRAPH
-"CALL db.idx.fulltext.queryNodes('Node', 'hello world') YIELD node, score RETURN score, node.val"
-1) 1) "score"
- 2) "node.val"
-2) 1) 1) "2"
- 2) "hello world"
- 2) 1) "1"
- 2) "hello to a different world"
-3) 1) "Cached execution: 1"
- 2) "Query internal execution time: 0.335401 milliseconds"
-```
-
-## Deleting a full-text index for a node label
-
-For a node label, the full-text index deletion syntax is:
-
-{% capture shell_15 %}
-GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.drop('Movie')"
-{% endcapture %}
-
-{% capture python_15 %}
-graph.query("CALL db.idx.fulltext.drop('Movie')")
-{% endcapture %}
-
-{% capture javascript_15 %}
-await graph.query("CALL db.idx.fulltext.drop('Movie')");
-{% endcapture %}
-
-{% capture java_15 %}
-graph.query("CALL db.idx.fulltext.drop('Movie')");
-{% endcapture %}
-
-{% capture rust_15 %}
-graph.query("CALL db.idx.fulltext.drop('Movie')").execute().await?;
-{% endcapture %}
-
-{% include code_tabs.html id="fulltext_drop_tabs" shell=shell_15 python=python_15 javascript=javascript_15 java=java_15 rust=rust_15 %}
-
-## Creating Full-Text indexing for Relation Labels
-To create a full-text index on the name property of all relations with the label Manager and enable phonetic search, use the following syntax:
-
-{% capture shell_16 %}
-GRAPH.QUERY DEMO_GRAPH "CREATE FULLTEXT INDEX FOR ()-[m:Manager]-() on (m.name)"
-{% endcapture %}
-
-{% capture python_16 %}
-graph.query("CREATE FULLTEXT INDEX FOR ()-[m:Manager]-() on (m.name)")
-{% endcapture %}
-
-{% capture javascript_16 %}
-await graph.query("CREATE FULLTEXT INDEX FOR ()-[m:Manager]-() on (m.name)");
-{% endcapture %}
-
-{% capture java_16 %}
-graph.query("CREATE FULLTEXT INDEX FOR ()-[m:Manager]-() on (m.name)");
-{% endcapture %}
-
-{% capture rust_16 %}
-graph.query("CREATE FULLTEXT INDEX FOR ()-[m:Manager]-() on (m.name)").execute().await?;
-{% endcapture %}
-
-{% include code_tabs.html id="fulltext_relation_create_tabs" shell=shell_16 python=python_16 javascript=javascript_16 java=java_16 rust=rust_16 %}
-## Querying with a Full-Text Index
-To search for specific words within the indexed relations, use:
-
-{% capture shell_17 %}
-GRAPH.QUERY DEMO_GRAPH
-"CALL db.idx.fulltext.queryRelationships('Manager', 'Charlie Munger') YIELD relationship RETURN relationship.name"
-{% endcapture %}
-
-{% capture python_17 %}
-result = graph.query("CALL db.idx.fulltext.queryRelationships('Manager', 'Charlie Munger') YIELD relationship RETURN relationship.name")
-{% endcapture %}
-
-{% capture javascript_17 %}
-const result = await graph.query("CALL db.idx.fulltext.queryRelationships('Manager', 'Charlie Munger') YIELD relationship RETURN relationship.name");
-{% endcapture %}
-
-{% capture java_17 %}
-ResultSet result = graph.query("CALL db.idx.fulltext.queryRelationships('Manager', 'Charlie Munger') YIELD relationship RETURN relationship.name");
-{% endcapture %}
-
-{% capture rust_17 %}
-let result = graph.query("CALL db.idx.fulltext.queryRelationships('Manager', 'Charlie Munger') YIELD relationship RETURN relationship.name").execute().await?;
-{% endcapture %}
-
-{% include code_tabs.html id="fulltext_relation_query_tabs" shell=shell_17 python=python_17 javascript=javascript_17 java=java_17 rust=rust_17 %}
-
-## Deleting a Full-Text Index
-To delete the full-text index for a specific relation label, use:
-
-{% capture shell_18 %}
-GRAPH.QUERY DEMO_GRAPH "CALL DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)"
-{% endcapture %}
-
-{% capture python_18 %}
-graph.query("CALL DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)")
-{% endcapture %}
-
-{% capture javascript_18 %}
-await graph.query("CALL DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)");
-{% endcapture %}
-
-{% capture java_18 %}
-graph.query("CALL DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)");
-{% endcapture %}
-
-{% capture rust_18 %}
-graph.query("CALL DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)").execute().await?;
-{% endcapture %}
-
-{% include code_tabs.html id="fulltext_relation_drop_tabs" shell=shell_18 python=python_18 javascript=javascript_18 java=java_18 rust=rust_18 %}
-
-## Vector indexing
-
-With the introduction of the `vector` data-type a new type of index was introduced.
-A vector index is a dedicated index for indexing and searching through vectors.
-
-To create this type of index use the following syntax:
-
-```cypher
-CREATE VECTOR INDEX FOR ON OPTIONS
-```
-
-The options are:
-```
-{
- dimension: INT, // Requiered, length of the vector to be indexed
- similarityFunction: STRING, // Requiered, currently only euclidean or cosine are allowed
- M: INT, // Optional, maximum number of outgoing edges per node. default 16
- efConstruction: INT, // Optional, number of candidates during construction. default 200
- efRuntime: INT // Optional, number of candidates during search. default 10
-}
-```
-
-For example, to create a vector index over all `Product` nodes `description` attribute
-use the following syntax:
-
-{% capture shell_19 %}
-CREATE VECTOR INDEX FOR (p:Product) ON (p.description) OPTIONS {dimension:128, similarityFunction:'euclidean'}
-{% endcapture %}
-
-{% capture python_19 %}
-graph.query("CREATE VECTOR INDEX FOR (p:Product) ON (p.description) OPTIONS {dimension:128, similarityFunction:'euclidean'}")
-{% endcapture %}
-
-{% capture javascript_19 %}
-await graph.query("CREATE VECTOR INDEX FOR (p:Product) ON (p.description) OPTIONS {dimension:128, similarityFunction:'euclidean'}");
-{% endcapture %}
-
-{% capture java_19 %}
-graph.query("CREATE VECTOR INDEX FOR (p:Product) ON (p.description) OPTIONS {dimension:128, similarityFunction:'euclidean'}");
-{% endcapture %}
-
-{% capture rust_19 %}
-graph.query("CREATE VECTOR INDEX FOR (p:Product) ON (p.description) OPTIONS {dimension:128, similarityFunction:'euclidean'}").execute().await?;
-{% endcapture %}
-
-{% include code_tabs.html id="vector_create_node_tabs" shell=shell_19 python=python_19 javascript=javascript_19 java=java_19 rust=rust_19 %}
-
-Similarly to create a vector index over all `Call` relationships `summary` attribute
-use the following syntax:
-
-{% capture shell_20 %}
-CREATE VECTOR INDEX FOR ()-[e:Call]->() ON (e.summary) OPTIONS {dimension:128, similarityFunction:'euclidean'}
-{% endcapture %}
-
-{% capture python_20 %}
-graph.query("CREATE VECTOR INDEX FOR ()-[e:Call]->() ON (e.summary) OPTIONS {dimension:128, similarityFunction:'euclidean'}")
-{% endcapture %}
-
-{% capture javascript_20 %}
-await graph.query("CREATE VECTOR INDEX FOR ()-[e:Call]->() ON (e.summary) OPTIONS {dimension:128, similarityFunction:'euclidean'}");
-{% endcapture %}
-
-{% capture java_20 %}
-graph.query("CREATE VECTOR INDEX FOR ()-[e:Call]->() ON (e.summary) OPTIONS {dimension:128, similarityFunction:'euclidean'}");
-{% endcapture %}
-
-{% capture rust_20 %}
-graph.query("CREATE VECTOR INDEX FOR ()-[e:Call]->() ON (e.summary) OPTIONS {dimension:128, similarityFunction:'euclidean'}").execute().await?;
-{% endcapture %}
-
-{% include code_tabs.html id="vector_create_relation_tabs" shell=shell_20 python=python_20 javascript=javascript_20 java=java_20 rust=rust_20 %}
-
-Please note, when creating a vector index, both the vector dimension and similarity function
-must be provided. At the moment the only supported similarity functions are 'euclidean' or 'cosine'.
-
-## Inserting vectors
-
-To create a new vector use the [vecf32](/cypher/functions#vector-functions) function
-as follows:
-
-{% capture shell_21 %}
-CREATE (p: Product {description: vecf32([2.1, 0.82, 1.3])})
-{% endcapture %}
-
-{% capture python_21 %}
-graph.query("CREATE (p: Product {description: vecf32([2.1, 0.82, 1.3])})")
-{% endcapture %}
-
-{% capture javascript_21 %}
-await graph.query("CREATE (p: Product {description: vecf32([2.1, 0.82, 1.3])})");
-{% endcapture %}
-
-{% capture java_21 %}
-graph.query("CREATE (p: Product {description: vecf32([2.1, 0.82, 1.3])})");
-{% endcapture %}
-
-{% capture rust_21 %}
-graph.query("CREATE (p: Product {description: vecf32([2.1, 0.82, 1.3])})").execute().await?;
-{% endcapture %}
-
-{% include code_tabs.html id="vector_insert_tabs" shell=shell_21 python=python_21 javascript=javascript_21 java=java_21 rust=rust_21 %}
-
-The above query creates a new `Product` node with a `description` attribute containing a vector.
-
-## Query vector index
-
-Vector indices are used to search for similar vectors to a given query vector
-using the similarity function as a measure of "distance".
-
-To query the index use either `db.idx.vector.queryNodes` for node retrieval or
-`db.idx.vector.queryRelationships` for relationships.
-
-```cypher
-CALL db.idx.vector.queryNodes(
- label: STRING,
- attribute: STRING,
- k: INTEGER,
- query: VECTOR
-) YIELD node, score
-```
-
-```cypher
-CALL db.idx.vector.queryRelationships(
- relationshipType: STRING,
- attribute: STRING,
- k: INTEGER,
- query: VECTOR
-) YIELD relationship, score
-```
-
-To query up to 10 similar `Product` descriptions to a given query description vector
-issue the following procedure call:
-
-{% capture shell_22 %}
-CALL db.idx.vector.queryNodes(
- 'Product',
- 'description',
- 10,
- vecf32(),
- ) YIELD node
-{% endcapture %}
-
-{% capture python_22 %}
-result = graph.query("CALL db.idx.vector.queryNodes('Product', 'description', 10, vecf32()) YIELD node")
-{% endcapture %}
-
-{% capture javascript_22 %}
-const result = await graph.query("CALL db.idx.vector.queryNodes('Product', 'description', 10, vecf32()) YIELD node");
-{% endcapture %}
-
-{% capture java_22 %}
-ResultSet result = graph.query("CALL db.idx.vector.queryNodes('Product', 'description', 10, vecf32()) YIELD node");
-{% endcapture %}
-
-{% capture rust_22 %}
-let result = graph.query("CALL db.idx.vector.queryNodes('Product', 'description', 10, vecf32()) YIELD node").execute().await?;
-{% endcapture %}
-
-{% include code_tabs.html id="vector_query_tabs" shell=shell_22 python=python_22 javascript=javascript_22 java=java_22 rust=rust_22 %}
-
-The procedure can yield both the indexed entity assigned to the found similar vector
-in addition to a similarity score of that entity.
-
-## Deleting a vector index
-
-To remove a vector index, simply issue the `drop index` command as follows:
-
-```cypher
-DROP VECTOR INDEX FOR ()
-```
-
-For example, to drop the vector index over Product description, invoke:
-
-{% capture shell_23 %}
-DROP VECTOR INDEX FOR (p:Product) ON (p.description)
-{% endcapture %}
-
-{% capture python_23 %}
-graph.query("DROP VECTOR INDEX FOR (p:Product) ON (p.description)")
-{% endcapture %}
-
-{% capture javascript_23 %}
-await graph.query("DROP VECTOR INDEX FOR (p:Product) ON (p.description)");
-{% endcapture %}
-
-{% capture java_23 %}
-graph.query("DROP VECTOR INDEX FOR (p:Product) ON (p.description)");
-{% endcapture %}
-
-{% capture rust_23 %}
-graph.query("DROP VECTOR INDEX FOR (p:Product) ON (p.description)").execute().await?;
-{% endcapture %}
-
-{% include code_tabs.html id="vector_drop_tabs" shell=shell_23 python=python_23 javascript=javascript_23 java=java_23 rust=rust_23 %}
diff --git a/cypher/indexing/fulltext-index.md b/cypher/indexing/fulltext-index.md
new file mode 100644
index 00000000..28625634
--- /dev/null
+++ b/cypher/indexing/fulltext-index.md
@@ -0,0 +1,636 @@
+---
+title: "Full-text Index"
+nav_order: 2
+description: >
+ FalkorDB provides full-text indices through procedure calls.
+parent: "Indexing"
+grand_parent: "Cypher Language"
+---
+
+# Full-text indexing
+
+FalkorDB leverages the indexing capabilities of [RediSearch](https://redis.io/docs/interact/search-and-query/) to provide full-text indices through procedure calls.
+
+## Creating a full-text index for a node label
+
+To construct a full-text index on the `title` property of all nodes with label `Movie`, use the syntax:
+
+{% capture shell_10 %}
+GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.createNodeIndex('Movie', 'title')"
+{% endcapture %}
+
+{% capture python_10 %}
+graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', 'title')")
+{% endcapture %}
+
+{% capture javascript_10 %}
+await graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', 'title')");
+{% endcapture %}
+
+{% capture java_10 %}
+graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', 'title')");
+{% endcapture %}
+
+{% capture rust_10 %}
+graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', 'title')").execute().await?;
+{% endcapture %}
+
+{% include code_tabs.html id="fulltext_create_tabs" shell=shell_10 python=python_10 javascript=javascript_10 java=java_10 rust=rust_10 %}
+
+More properties can be added to this index by adding their names to the above set of arguments, or using this syntax again with the additional names.
+
+{% capture shell_11 %}
+GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.createNodeIndex('Person', 'firstName', 'lastName')"
+{% endcapture %}
+
+{% capture python_11 %}
+graph.query("CALL db.idx.fulltext.createNodeIndex('Person', 'firstName', 'lastName')")
+{% endcapture %}
+
+{% capture javascript_11 %}
+await graph.query("CALL db.idx.fulltext.createNodeIndex('Person', 'firstName', 'lastName')");
+{% endcapture %}
+
+{% capture java_11 %}
+graph.query("CALL db.idx.fulltext.createNodeIndex('Person', 'firstName', 'lastName')");
+{% endcapture %}
+
+{% capture rust_11 %}
+graph.query("CALL db.idx.fulltext.createNodeIndex('Person', 'firstName', 'lastName')").execute().await?;
+{% endcapture %}
+
+{% include code_tabs.html id="fulltext_multi_property_tabs" shell=shell_11 python=python_11 javascript=javascript_11 java=java_11 rust=rust_11 %}
+
+Index configuration options:
+
+1. Language - Define which language to use for stemming text, which is adding the base form of a word to the index. This allows the query for "going" to also return results for "go" and "gone", for example.
+2. Stopwords - These are words that are usually so common that they do not add much information to search, but take up a lot of space and CPU time in the index.
+
+To construct a full-text index on the `title` property using `German` language and using custom stopwords of all nodes with label `Movie`, use the syntax:
+
+{% capture shell_12 %}
+GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.createNodeIndex({ label: 'Movie', language: 'German', stopwords: ['a', 'ab'] }, 'title')"
+{% endcapture %}
+
+{% capture python_12 %}
+graph.query("CALL db.idx.fulltext.createNodeIndex({ label: 'Movie', language: 'German', stopwords: ['a', 'ab'] }, 'title')")
+{% endcapture %}
+
+{% capture javascript_12 %}
+await graph.query("CALL db.idx.fulltext.createNodeIndex({ label: 'Movie', language: 'German', stopwords: ['a', 'ab'] }, 'title')");
+{% endcapture %}
+
+{% capture java_12 %}
+graph.query("CALL db.idx.fulltext.createNodeIndex({ label: 'Movie', language: 'German', stopwords: ['a', 'ab'] }, 'title')");
+{% endcapture %}
+
+{% capture rust_12 %}
+graph.query("CALL db.idx.fulltext.createNodeIndex({ label: 'Movie', language: 'German', stopwords: ['a', 'ab'] }, 'title')").execute().await?;
+{% endcapture %}
+
+{% include code_tabs.html id="fulltext_config_tabs" shell=shell_12 python=python_12 javascript=javascript_12 java=java_12 rust=rust_12 %}
+
+Additional field configuration options:
+
+1. Weight - The importance of the text in the field
+2. Nostem - Skip stemming when indexing text
+3. Phonetic - Enable phonetic search on the text
+
+To construct a full-text index on the `title` property with phonetic search of all nodes with label `Movie`, use the syntax:
+
+{% capture shell_13 %}
+GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.createNodeIndex('Movie', {field: 'title', phonetic: 'dm:en'})"
+{% endcapture %}
+
+{% capture python_13 %}
+graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', {field: 'title', phonetic: 'dm:en'})")
+{% endcapture %}
+
+{% capture javascript_13 %}
+await graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', {field: 'title', phonetic: 'dm:en'})");
+{% endcapture %}
+
+{% capture java_13 %}
+graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', {field: 'title', phonetic: 'dm:en'})");
+{% endcapture %}
+
+{% capture rust_13 %}
+graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', {field: 'title', phonetic: 'dm:en'})").execute().await?;
+{% endcapture %}
+
+{% include code_tabs.html id="fulltext_phonetic_tabs" shell=shell_13 python=python_13 javascript=javascript_13 java=java_13 rust=rust_13 %}
+
+## Query Syntax and Features
+
+FalkorDB uses [RediSearch query syntax](https://redis.io/docs/latest/develop/ai/search-and-query/advanced-concepts/query_syntax/) which provides powerful search capabilities including fuzzy matching, prefix matching, and tokenization.
+
+### Tokenization
+
+When text is indexed, it is automatically tokenized (split into words). By default, text is split on whitespace and punctuation. This allows you to search for individual words within larger text fields.
+
+For example, if you index a `title` property containing "The Lord of the Rings", you can search for any of the individual words like "Lord" or "Rings".
+
+### Prefix Matching
+
+Prefix matching allows you to search for words that start with a specific prefix using the `*` wildcard. This is useful for autocomplete functionality or when you want to match word variations.
+
+{% capture shell_prefix %}
+# Find all movies with titles containing words starting with "Jun"
+GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.queryNodes('Movie', 'Jun*') YIELD node RETURN node.title"
+# This would match "Jungle", "June", "Junior", etc.
+{% endcapture %}
+
+{% capture python_prefix %}
+# Find all movies with titles containing words starting with "Jun"
+result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jun*') YIELD node RETURN node.title")
+for record in result:
+ print(record["node.title"])
+# This would match "Jungle", "June", "Junior", etc.
+{% endcapture %}
+
+{% capture javascript_prefix %}
+// Find all movies with titles containing words starting with "Jun"
+const result = await graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jun*') YIELD node RETURN node.title");
+for (const record of result.data) {
+ console.log(record["node.title"]);
+}
+// This would match "Jungle", "June", "Junior", etc.
+{% endcapture %}
+
+{% capture java_prefix %}
+// Find all movies with titles containing words starting with "Jun"
+ResultSet result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jun*') YIELD node RETURN node.title");
+for (Record record : result) {
+ System.out.println(record.get("node.title"));
+}
+// This would match "Jungle", "June", "Junior", etc.
+{% endcapture %}
+
+{% capture rust_prefix %}
+// Find all movies with titles containing words starting with "Jun"
+let result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jun*') YIELD node RETURN node.title").execute().await?;
+for record in result.data() {
+ println!("{}", record["node.title"]);
+}
+// This would match "Jungle", "June", "Junior", etc.
+{% endcapture %}
+
+{% include code_tabs.html id="fulltext_prefix_tabs" shell=shell_prefix python=python_prefix javascript=javascript_prefix java=java_prefix rust=rust_prefix %}
+
+**Note:** Prefix matching only works at the end of a word (e.g., `Jun*`). The wildcard must appear at the end of the search term.
+
+### Fuzzy Matching
+
+Fuzzy matching allows you to find words that are similar to your search term, accounting for typos and spelling variations. Use the `%` symbol followed by the Levenshtein distance (number of character changes allowed).
+
+{% capture shell_fuzzy %}
+# Find movies with titles containing words similar to "Jangle" (allowing 1 character difference)
+GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.queryNodes('Movie', '%Jangle%1') YIELD node RETURN node.title"
+# This would match "Jungle" (1 character different)
+
+# Allow up to 2 character differences
+GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.queryNodes('Movie', '%Jngle%2') YIELD node RETURN node.title"
+# This would also match "Jungle" (1 character missing)
+{% endcapture %}
+
+{% capture python_fuzzy %}
+# Find movies with titles containing words similar to "Jangle" (allowing 1 character difference)
+result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', '%Jangle%1') YIELD node RETURN node.title")
+for record in result:
+ print(record["node.title"])
+# This would match "Jungle" (1 character different)
+
+# Allow up to 2 character differences
+result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', '%Jngle%2') YIELD node RETURN node.title")
+# This would also match "Jungle" (1 character missing)
+{% endcapture %}
+
+{% capture javascript_fuzzy %}
+// Find movies with titles containing words similar to "Jangle" (allowing 1 character difference)
+const result = await graph.query("CALL db.idx.fulltext.queryNodes('Movie', '%Jangle%1') YIELD node RETURN node.title");
+for (const record of result.data) {
+ console.log(record["node.title"]);
+}
+// This would match "Jungle" (1 character different)
+
+// Allow up to 2 character differences
+const result2 = await graph.query("CALL db.idx.fulltext.queryNodes('Movie', '%Jngle%2') YIELD node RETURN node.title");
+// This would also match "Jungle" (1 character missing)
+{% endcapture %}
+
+{% capture java_fuzzy %}
+// Find movies with titles containing words similar to "Jangle" (allowing 1 character difference)
+ResultSet result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', '%Jangle%1') YIELD node RETURN node.title");
+for (Record record : result) {
+ System.out.println(record.get("node.title"));
+}
+// This would match "Jungle" (1 character different)
+
+// Allow up to 2 character differences
+ResultSet result2 = graph.query("CALL db.idx.fulltext.queryNodes('Movie', '%Jngle%2') YIELD node RETURN node.title");
+// This would also match "Jungle" (1 character missing)
+{% endcapture %}
+
+{% capture rust_fuzzy %}
+// Find movies with titles containing words similar to "Jangle" (allowing 1 character difference)
+let result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', '%Jangle%1') YIELD node RETURN node.title").execute().await?;
+for record in result.data() {
+ println!("{}", record["node.title"]);
+}
+// This would match "Jungle" (1 character different)
+
+// Allow up to 2 character differences
+let result2 = graph.query("CALL db.idx.fulltext.queryNodes('Movie', '%Jngle%2') YIELD node RETURN node.title").execute().await?;
+// This would also match "Jungle" (1 character missing)
+{% endcapture %}
+
+{% include code_tabs.html id="fulltext_fuzzy_tabs" shell=shell_fuzzy python=python_fuzzy javascript=javascript_fuzzy java=java_fuzzy rust=rust_fuzzy %}
+
+**Fuzzy matching syntax:** `%term%distance` where:
+- `term` is the word to match
+- `distance` is the maximum Levenshtein distance (1-3, default is 1 if not specified)
+
+**Note:** Fuzzy matching is computationally more expensive than exact or prefix matching, so use it judiciously on large datasets.
+
+### Combining Query Features
+
+You can combine multiple search terms using boolean operators:
+
+- `AND` (or space): All terms must match
+- `OR` (`|`): At least one term must match
+- `NOT` (`-`): Term must not be present
+
+{% capture shell_combined %}
+# Find movies with "Jungle" AND "Book" in the title
+GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.queryNodes('Movie', 'Jungle Book') YIELD node RETURN node.title"
+
+# Find movies with "Jungle" OR "Forest" in the title
+GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.queryNodes('Movie', 'Jungle|Forest') YIELD node RETURN node.title"
+
+# Find movies with "Book" but NOT "Jungle"
+GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.queryNodes('Movie', 'Book -Jungle') YIELD node RETURN node.title"
+
+# Combine prefix and fuzzy matching: Find "Jun*" OR words similar to "Forst"
+GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.queryNodes('Movie', 'Jun*|%Forst%1') YIELD node RETURN node.title"
+{% endcapture %}
+
+{% capture python_combined %}
+# Find movies with "Jungle" AND "Book" in the title
+result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jungle Book') YIELD node RETURN node.title")
+
+# Find movies with "Jungle" OR "Forest" in the title
+result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jungle|Forest') YIELD node RETURN node.title")
+
+# Find movies with "Book" but NOT "Jungle"
+result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Book -Jungle') YIELD node RETURN node.title")
+
+# Combine prefix and fuzzy matching
+result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jun*|%Forst%1') YIELD node RETURN node.title")
+{% endcapture %}
+
+{% capture javascript_combined %}
+// Find movies with "Jungle" AND "Book" in the title
+const result = await graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jungle Book') YIELD node RETURN node.title");
+
+// Find movies with "Jungle" OR "Forest" in the title
+const result2 = await graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jungle|Forest') YIELD node RETURN node.title");
+
+// Find movies with "Book" but NOT "Jungle"
+const result3 = await graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Book -Jungle') YIELD node RETURN node.title");
+
+// Combine prefix and fuzzy matching
+const result4 = await graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jun*|%Forst%1') YIELD node RETURN node.title");
+{% endcapture %}
+
+{% capture java_combined %}
+// Find movies with "Jungle" AND "Book" in the title
+ResultSet result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jungle Book') YIELD node RETURN node.title");
+
+// Find movies with "Jungle" OR "Forest" in the title
+ResultSet result2 = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jungle|Forest') YIELD node RETURN node.title");
+
+// Find movies with "Book" but NOT "Jungle"
+ResultSet result3 = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Book -Jungle') YIELD node RETURN node.title");
+
+// Combine prefix and fuzzy matching
+ResultSet result4 = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jun*|%Forst%1') YIELD node RETURN node.title");
+{% endcapture %}
+
+{% capture rust_combined %}
+// Find movies with "Jungle" AND "Book" in the title
+let result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jungle Book') YIELD node RETURN node.title").execute().await?;
+
+// Find movies with "Jungle" OR "Forest" in the title
+let result2 = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jungle|Forest') YIELD node RETURN node.title").execute().await?;
+
+// Find movies with "Book" but NOT "Jungle"
+let result3 = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Book -Jungle') YIELD node RETURN node.title").execute().await?;
+
+// Combine prefix and fuzzy matching
+let result4 = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jun*|%Forst%1') YIELD node RETURN node.title").execute().await?;
+{% endcapture %}
+
+{% include code_tabs.html id="fulltext_combined_tabs" shell=shell_combined python=python_combined javascript=javascript_combined java=java_combined rust=rust_combined %}
+
+For more advanced query syntax features, see the [RediSearch query syntax documentation](https://redis.io/docs/latest/develop/ai/search-and-query/advanced-concepts/query_syntax/).
+
+## Utilizing a full-text index for a node label
+
+An index can be invoked to match any whole words contained within:
+
+{% capture shell_14 %}
+GRAPH.QUERY DEMO_GRAPH
+"CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node.title"
+1) 1) "node.title"
+2) 1) 1) "The Jungle Book"
+ 2) 1) "The Book of Life"
+3) 1) "Query internal execution time: 0.927409 milliseconds"
+{% endcapture %}
+
+{% capture python_14 %}
+result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node.title")
+for record in result:
+ print(record["node.title"])
+# Output:
+# The Jungle Book
+# The Book of Life
+{% endcapture %}
+
+{% capture javascript_14 %}
+const result = await graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node.title");
+for (const record of result.data) {
+ console.log(record["node.title"]);
+}
+// Output:
+// The Jungle Book
+// The Book of Life
+{% endcapture %}
+
+{% capture java_14 %}
+ResultSet result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node.title");
+for (Record record : result) {
+ System.out.println(record.get("node.title"));
+}
+// Output:
+// The Jungle Book
+// The Book of Life
+{% endcapture %}
+
+{% capture rust_14 %}
+let result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node.title").execute().await?;
+for record in result.data() {
+ println!("{}", record["node.title"]);
+}
+// Output:
+// The Jungle Book
+// The Book of Life
+{% endcapture %}
+
+{% include code_tabs.html id="fulltext_query_tabs" shell=shell_14 python=python_14 javascript=javascript_14 java=java_14 rust=rust_14 %}
+
+This CALL clause can be interleaved with other Cypher clauses to perform more elaborate manipulations:
+
+```sh
+GRAPH.QUERY DEMO_GRAPH
+"CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node AS m
+WHERE m.genre = 'Adventure'
+RETURN m ORDER BY m.rating"
+1) 1) "m"
+2) 1) 1) 1) 1) "id"
+ 2) (integer) 1168
+ 2) 1) "labels"
+ 2) 1) "Movie"
+ 3) 1) "properties"
+ 2) 1) 1) "genre"
+ 2) "Adventure"
+ 2) 1) "rating"
+ 2) "7.6"
+ 3) 1) "votes"
+ 2) (integer) 151342
+ 4) 1) "year"
+ 2) (integer) 2016
+ 5) 1) "title"
+ 2) "The Jungle Book"
+3) 1) "Query internal execution time: 0.226914 milliseconds"
+```
+
+In addition to yielding matching nodes, full-text index scans will return the score of each node. This is the [TF-IDF](https://redis.io/docs/interact/search-and-query/advanced-concepts/scoring/#tfidf-default) score of the node, which is informed by how many times the search terms appear in the node and how closely grouped they are. This can be observed in the example:
+
+```sh
+GRAPH.QUERY DEMO_GRAPH
+"CALL db.idx.fulltext.queryNodes('Node', 'hello world') YIELD node, score RETURN score, node.val"
+1) 1) "score"
+ 2) "node.val"
+2) 1) 1) "2"
+ 2) "hello world"
+ 2) 1) "1"
+ 2) "hello to a different world"
+3) 1) "Cached execution: 1"
+ 2) "Query internal execution time: 0.335401 milliseconds"
+```
+
+## Deleting a full-text index for a node label
+
+For a node label, the full-text index deletion syntax is:
+
+{% capture shell_15 %}
+GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.drop('Movie')"
+{% endcapture %}
+
+{% capture python_15 %}
+graph.query("CALL db.idx.fulltext.drop('Movie')")
+{% endcapture %}
+
+{% capture javascript_15 %}
+await graph.query("CALL db.idx.fulltext.drop('Movie')");
+{% endcapture %}
+
+{% capture java_15 %}
+graph.query("CALL db.idx.fulltext.drop('Movie')");
+{% endcapture %}
+
+{% capture rust_15 %}
+graph.query("CALL db.idx.fulltext.drop('Movie')").execute().await?;
+{% endcapture %}
+
+{% include code_tabs.html id="fulltext_drop_tabs" shell=shell_15 python=python_15 javascript=javascript_15 java=java_15 rust=rust_15 %}
+
+## Creating Full-Text indexing for Relation Labels
+To create a full-text index on the name property of all relations with the label Manager and enable phonetic search, use the following syntax:
+
+{% capture shell_16 %}
+GRAPH.QUERY DEMO_GRAPH "CREATE FULLTEXT INDEX FOR ()-[m:Manager]-() on (m.name)"
+{% endcapture %}
+
+{% capture python_16 %}
+graph.query("CREATE FULLTEXT INDEX FOR ()-[m:Manager]-() on (m.name)")
+{% endcapture %}
+
+{% capture javascript_16 %}
+await graph.query("CREATE FULLTEXT INDEX FOR ()-[m:Manager]-() on (m.name)");
+{% endcapture %}
+
+{% capture java_16 %}
+graph.query("CREATE FULLTEXT INDEX FOR ()-[m:Manager]-() on (m.name)");
+{% endcapture %}
+
+{% capture rust_16 %}
+graph.query("CREATE FULLTEXT INDEX FOR ()-[m:Manager]-() on (m.name)").execute().await?;
+{% endcapture %}
+
+{% include code_tabs.html id="fulltext_relation_create_tabs" shell=shell_16 python=python_16 javascript=javascript_16 java=java_16 rust=rust_16 %}
+## Querying with a Full-Text Index
+To search for specific words within the indexed relations, use:
+
+{% capture shell_17 %}
+GRAPH.QUERY DEMO_GRAPH
+"CALL db.idx.fulltext.queryRelationships('Manager', 'Charlie Munger') YIELD relationship RETURN relationship.name"
+{% endcapture %}
+
+{% capture python_17 %}
+result = graph.query("CALL db.idx.fulltext.queryRelationships('Manager', 'Charlie Munger') YIELD relationship RETURN relationship.name")
+{% endcapture %}
+
+{% capture javascript_17 %}
+const result = await graph.query("CALL db.idx.fulltext.queryRelationships('Manager', 'Charlie Munger') YIELD relationship RETURN relationship.name");
+{% endcapture %}
+
+{% capture java_17 %}
+ResultSet result = graph.query("CALL db.idx.fulltext.queryRelationships('Manager', 'Charlie Munger') YIELD relationship RETURN relationship.name");
+{% endcapture %}
+
+{% capture rust_17 %}
+let result = graph.query("CALL db.idx.fulltext.queryRelationships('Manager', 'Charlie Munger') YIELD relationship RETURN relationship.name").execute().await?;
+{% endcapture %}
+
+{% include code_tabs.html id="fulltext_relation_query_tabs" shell=shell_17 python=python_17 javascript=javascript_17 java=java_17 rust=rust_17 %}
+
+## Deleting a Full-Text Index
+To delete the full-text index for a specific relation label, use:
+
+{% capture shell_18 %}
+GRAPH.QUERY DEMO_GRAPH "DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)"
+{% endcapture %}
+
+{% capture python_18 %}
+graph.query("DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)")
+{% endcapture %}
+
+{% capture javascript_18 %}
+await graph.query("DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)");
+{% endcapture %}
+
+{% capture java_18 %}
+graph.query("DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)");
+{% endcapture %}
+
+{% capture rust_18 %}
+graph.query("DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)").execute().await?;
+{% endcapture %}
+
+{% include code_tabs.html id="fulltext_relation_drop_tabs" shell=shell_18 python=python_18 javascript=javascript_18 java=java_18 rust=rust_18 %}
+
+## Index Management
+
+### Listing Full-text Indexes
+
+To view all indexes (including full-text) in your graph, use:
+
+```cypher
+CALL db.indexes()
+```
+
+This returns information about all indexes, with full-text indexes marked with type `FULLTEXT`.
+
+## Performance Tradeoffs and Best Practices
+
+### When to Use Full-text Indexes
+
+Full-text indexes are ideal for:
+- **Text-heavy search**: Searching within large text fields like descriptions, articles, or comments
+- **Partial word matching**: When users might not know the exact text
+- **Fuzzy search**: Handling typos and spelling variations
+- **Multi-word queries**: Searching for multiple terms with boolean logic
+
+### When NOT to Use Full-text Indexes
+
+Full-text indexes are not optimal for:
+- **Exact numeric filtering**: Use range indexes instead for numeric comparisons
+- **Exact-match queries**: Range indexes are more efficient for exact property matches
+- **Small or structured data**: For short, well-defined strings, range indexes may be sufficient
+
+### Performance Considerations
+
+**Benefits:**
+- Enables sophisticated text search capabilities (fuzzy, prefix, phonetic)
+- Supports stemming and language-specific optimizations
+- Returns relevance scores (TF-IDF) for ranking results
+
+**Costs:**
+- **Write overhead**: Text must be tokenized and indexed on write
+- **Storage**: Requires more space than range indexes due to tokenization and inverted indices
+- **Configuration complexity**: Language, stopwords, and stemming settings affect results
+- **Query performance**: Fuzzy matching is more expensive than exact matching
+
+**Recommendations:**
+- Choose the correct language setting for proper stemming
+- Configure appropriate stopwords for your use case
+- Use prefix matching (`*`) for autocomplete rather than full fuzzy search when possible
+- Test query performance with realistic data volumes
+- Consider the tradeoff between index configurability and query performance
+
+### Configuration Best Practices
+
+**Language Selection:**
+- Wrong language settings can produce poor stemming results
+- Example: Searching "running" with English stemming finds "run", but German stemming won't
+
+**Stopwords:**
+- Default stopwords are optimized for general text
+- Customize stopwords for domain-specific applications (e.g., legal, medical, technical documents)
+- Too many stopwords can hurt precision; too few increase index size
+
+**Phonetic Search:**
+- Useful for name searches and when spelling variations are common
+- Increases index size and query time
+- Double Metaphone (`dm:en`) is recommended for English
+
+## Verifying Full-text Index Usage
+
+Use `GRAPH.EXPLAIN` to verify that full-text queries use the index:
+
+{% capture shell_ft_verify %}
+# Check if full-text index is used
+GRAPH.EXPLAIN DEMO_GRAPH "CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node"
+# Output shows: ProcedureCall | db.idx.fulltext.queryNodes
+{% endcapture %}
+
+{% capture python_ft_verify %}
+# Check if full-text index is used
+result = graph.explain("CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node")
+print(result)
+# Output shows: ProcedureCall | db.idx.fulltext.queryNodes
+{% endcapture %}
+
+{% capture javascript_ft_verify %}
+// Check if full-text index is used
+const result = await graph.explain("CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node");
+console.log(result);
+// Output shows: ProcedureCall | db.idx.fulltext.queryNodes
+{% endcapture %}
+
+{% capture java_ft_verify %}
+// Check if full-text index is used
+String result = graph.explain("CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node");
+System.out.println(result);
+// Output shows: ProcedureCall | db.idx.fulltext.queryNodes
+{% endcapture %}
+
+{% capture rust_ft_verify %}
+// Check if full-text index is used
+let result = graph.explain("CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node").execute().await?;
+println!("{}", result);
+// Output shows: ProcedureCall | db.idx.fulltext.queryNodes
+{% endcapture %}
+
+{% include code_tabs.html id="fulltext_verify_tabs" shell=shell_ft_verify python=python_ft_verify javascript=javascript_ft_verify java=java_ft_verify rust=rust_ft_verify %}
diff --git a/cypher/indexing/index.md b/cypher/indexing/index.md
new file mode 100644
index 00000000..45acf1f1
--- /dev/null
+++ b/cypher/indexing/index.md
@@ -0,0 +1,34 @@
+---
+title: "Indexing"
+nav_order: 21
+description: >
+ FalkorDB supports single-property indexes for node labels and for relationship type. String, numeric, and geospatial data types can be indexed.
+parent: "Cypher Language"
+has_children: true
+redirect_from:
+ - /cypher/indexing.html
+---
+
+# Indexing
+
+FalkorDB provides multiple types of indexes to optimize query performance and enable efficient data retrieval. Each index type is designed for specific use cases and data patterns.
+
+## Index Types
+
+FalkorDB supports the following index types:
+
+### [Range Index](./range-index)
+
+Range indexes support single-property indexes for node labels and relationship types. String, numeric, and geospatial data types can be indexed. These indexes automatically optimize queries with filters on indexed properties.
+
+### [Full-text Index](./fulltext-index)
+
+Full-text indexes leverage RediSearch capabilities to provide powerful text search functionality. They support features like stemming, stopwords, phonetic search, and scoring based on TF-IDF.
+
+### [Vector Index](./vector-index)
+
+Vector indexes enable similarity search on vector embeddings. These indexes are essential for AI and machine learning applications, supporting operations like nearest neighbor search with configurable similarity functions (euclidean or cosine).
+
+---
+
+Choose an index type from the navigation menu to learn more about creating, querying, and managing that specific type of index.
diff --git a/cypher/indexing/range-index.md b/cypher/indexing/range-index.md
new file mode 100644
index 00000000..d4438919
--- /dev/null
+++ b/cypher/indexing/range-index.md
@@ -0,0 +1,488 @@
+---
+title: "Range Index"
+nav_order: 1
+description: >
+ FalkorDB supports single-property indexes for node labels and for relationship type. String, numeric, and geospatial data types can be indexed.
+parent: "Indexing"
+grand_parent: "Cypher Language"
+---
+
+# Range Index
+
+FalkorDB supports single-property indexes for node labels and for relationship type. String, numeric, and geospatial data types can be indexed.
+
+## Supported Data Types
+
+Range indexes support the following data types:
+- **String**: Text values for exact matching and range queries
+- **Numeric**: Integer and floating-point numbers for range comparisons
+- **Geospatial**: Point data types for location-based queries
+- **Arrays**: Single-property arrays containing scalar values (integers, floats, strings)
+
+**Note**: Complex types like nested arrays, maps, or vectors are not supported for range indexing.
+
+## Creating an index for a node label
+
+For a node label, the index creation syntax is:
+
+{% capture shell_0 %}
+GRAPH.QUERY DEMO_GRAPH "CREATE INDEX FOR (p:Person) ON (p.age)"
+{% endcapture %}
+
+{% capture python_0 %}
+graph.query("CREATE INDEX FOR (p:Person) ON (p.age)")
+{% endcapture %}
+
+{% capture javascript_0 %}
+await graph.query("CREATE INDEX FOR (p:Person) ON (p.age)");
+{% endcapture %}
+
+{% capture java_0 %}
+graph.query("CREATE INDEX FOR (p:Person) ON (p.age)");
+{% endcapture %}
+
+{% capture rust_0 %}
+graph.query("CREATE INDEX FOR (p:Person) ON (p.age)").execute().await?;
+{% endcapture %}
+
+{% include code_tabs.html id="create_index_tabs" shell=shell_0 python=python_0 javascript=javascript_0 java=java_0 rust=rust_0 %}
+
+An old syntax is also supported:
+
+{% capture shell_1 %}
+GRAPH.QUERY DEMO_GRAPH "CREATE INDEX ON :Person(age)"
+{% endcapture %}
+
+{% capture python_1 %}
+graph.query("CREATE INDEX ON :Person(age)")
+{% endcapture %}
+
+{% capture javascript_1 %}
+await graph.query("CREATE INDEX ON :Person(age)");
+{% endcapture %}
+
+{% capture java_1 %}
+graph.query("CREATE INDEX ON :Person(age)");
+{% endcapture %}
+
+{% capture rust_1 %}
+graph.query("CREATE INDEX ON :Person(age)").execute().await?;
+{% endcapture %}
+
+{% include code_tabs.html id="old_syntax_tabs" shell=shell_1 python=python_1 javascript=javascript_1 java=java_1 rust=rust_1 %}
+
+After an index is explicitly created, it will automatically be used by queries that reference that label and any indexed property in a filter.
+
+{% capture shell_2 %}
+GRAPH.EXPLAIN DEMO_GRAPH "MATCH (p:Person) WHERE p.age > 80 RETURN p"
+1) "Results"
+2) " Project"
+3) " Index Scan | (p:Person)"
+{% endcapture %}
+
+{% capture python_2 %}
+result = graph.explain("MATCH (p:Person) WHERE p.age > 80 RETURN p")
+print(result)
+# Output:
+# Results
+# Project
+# Index Scan | (p:Person)
+{% endcapture %}
+
+{% capture javascript_2 %}
+const result = await graph.explain("MATCH (p:Person) WHERE p.age > 80 RETURN p");
+console.log(result);
+// Output:
+// Results
+// Project
+// Index Scan | (p:Person)
+{% endcapture %}
+
+{% capture java_2 %}
+String result = graph.explain("MATCH (p:Person) WHERE p.age > 80 RETURN p");
+System.out.println(result);
+// Output:
+// Results
+// Project
+// Index Scan | (p:Person)
+{% endcapture %}
+
+{% capture rust_2 %}
+let result = graph.explain("MATCH (p:Person) WHERE p.age > 80 RETURN p").execute().await?;
+println!("{}", result);
+// Output:
+// Results
+// Project
+// Index Scan | (p:Person)
+{% endcapture %}
+
+{% include code_tabs.html id="explain_tabs" shell=shell_2 python=python_2 javascript=javascript_2 java=java_2 rust=rust_2 %}
+
+This can significantly improve the runtime of queries with very specific filters. An index on `:employer(name)`, for example, will dramatically benefit the query:
+
+{% capture shell_3 %}
+GRAPH.QUERY DEMO_GRAPH
+"MATCH (:Employer {name: 'Dunder Mifflin'})-[:EMPLOYS]->(p:Person) RETURN p"
+{% endcapture %}
+
+{% capture python_3 %}
+result = graph.query("MATCH (:Employer {name: 'Dunder Mifflin'})-[:EMPLOYS]->(p:Person) RETURN p")
+{% endcapture %}
+
+{% capture javascript_3 %}
+const result = await graph.query("MATCH (:Employer {name: 'Dunder Mifflin'})-[:EMPLOYS]->(p:Person) RETURN p");
+{% endcapture %}
+
+{% capture java_3 %}
+ResultSet result = graph.query("MATCH (:Employer {name: 'Dunder Mifflin'})-[:EMPLOYS]->(p:Person) RETURN p");
+{% endcapture %}
+
+{% capture rust_3 %}
+let result = graph.query("MATCH (:Employer {name: 'Dunder Mifflin'})-[:EMPLOYS]->(p:Person) RETURN p").execute().await?;
+{% endcapture %}
+
+{% include code_tabs.html id="employer_query_tabs" shell=shell_3 python=python_3 javascript=javascript_3 java=java_3 rust=rust_3 %}
+
+An example of utilizing a geospatial index to find `Employer` nodes within 5 kilometers of Scranton are:
+
+{% capture shell_4 %}
+GRAPH.QUERY DEMO_GRAPH
+"WITH point({latitude:41.4045886, longitude:-75.6969532}) AS scranton MATCH (e:Employer) WHERE distance(e.location, scranton) < 5000 RETURN e"
+{% endcapture %}
+
+{% capture python_4 %}
+result = graph.query("WITH point({latitude:41.4045886, longitude:-75.6969532}) AS scranton MATCH (e:Employer) WHERE distance(e.location, scranton) < 5000 RETURN e")
+{% endcapture %}
+
+{% capture javascript_4 %}
+const result = await graph.query("WITH point({latitude:41.4045886, longitude:-75.6969532}) AS scranton MATCH (e:Employer) WHERE distance(e.location, scranton) < 5000 RETURN e");
+{% endcapture %}
+
+{% capture java_4 %}
+ResultSet result = graph.query("WITH point({latitude:41.4045886, longitude:-75.6969532}) AS scranton MATCH (e:Employer) WHERE distance(e.location, scranton) < 5000 RETURN e");
+{% endcapture %}
+
+{% capture rust_4 %}
+let result = graph.query("WITH point({latitude:41.4045886, longitude:-75.6969532}) AS scranton MATCH (e:Employer) WHERE distance(e.location, scranton) < 5000 RETURN e").execute().await?;
+{% endcapture %}
+
+{% include code_tabs.html id="geospatial_tabs" shell=shell_4 python=python_4 javascript=javascript_4 java=java_4 rust=rust_4 %}
+
+Geospatial indexes can currently only be leveraged with `<` and `<=` filters; matching nodes outside the given radius are matched using conventional traversal.
+
+## Creating an index for a relationship type
+
+For a relationship type, the index creation syntax is:
+
+{% capture shell_5 %}
+GRAPH.QUERY DEMO_GRAPH "CREATE INDEX FOR ()-[f:FOLLOW]-() ON (f.created_at)"
+{% endcapture %}
+
+{% capture python_5 %}
+graph.query("CREATE INDEX FOR ()-[f:FOLLOW]-() ON (f.created_at)")
+{% endcapture %}
+
+{% capture javascript_5 %}
+await graph.query("CREATE INDEX FOR ()-[f:FOLLOW]-() ON (f.created_at)");
+{% endcapture %}
+
+{% capture java_5 %}
+graph.query("CREATE INDEX FOR ()-[f:FOLLOW]-() ON (f.created_at)");
+{% endcapture %}
+
+{% capture rust_5 %}
+graph.query("CREATE INDEX FOR ()-[f:FOLLOW]-() ON (f.created_at)").execute().await?;
+{% endcapture %}
+
+{% include code_tabs.html id="relationship_index_tabs" shell=shell_5 python=python_5 javascript=javascript_5 java=java_5 rust=rust_5 %}
+
+Then the execution plan for using the index:
+
+{% capture shell_6 %}
+GRAPH.EXPLAIN DEMO_GRAPH "MATCH (p:Person {id: 0})-[f:FOLLOW]->(fp) WHERE 0 < f.created_at AND f.created_at < 1000 RETURN fp"
+1) "Results"
+2) " Project"
+3) " Edge By Index Scan | [f:FOLLOW]"
+4) " Node By Index Scan | (p:Person)"
+{% endcapture %}
+
+{% capture python_6 %}
+result = graph.explain("MATCH (p:Person {id: 0})-[f:FOLLOW]->(fp) WHERE 0 < f.created_at AND f.created_at < 1000 RETURN fp")
+print(result)
+# Output:
+# Results
+# Project
+# Edge By Index Scan | [f:FOLLOW]
+# Node By Index Scan | (p:Person)
+{% endcapture %}
+
+{% capture javascript_6 %}
+const result = await graph.explain("MATCH (p:Person {id: 0})-[f:FOLLOW]->(fp) WHERE 0 < f.created_at AND f.created_at < 1000 RETURN fp");
+console.log(result);
+// Output:
+// Results
+// Project
+// Edge By Index Scan | [f:FOLLOW]
+// Node By Index Scan | (p:Person)
+{% endcapture %}
+
+{% capture java_6 %}
+String result = graph.explain("MATCH (p:Person {id: 0})-[f:FOLLOW]->(fp) WHERE 0 < f.created_at AND f.created_at < 1000 RETURN fp");
+System.out.println(result);
+// Output:
+// Results
+// Project
+// Edge By Index Scan | [f:FOLLOW]
+// Node By Index Scan | (p:Person)
+{% endcapture %}
+
+{% capture rust_6 %}
+let result = graph.explain("MATCH (p:Person {id: 0})-[f:FOLLOW]->(fp) WHERE 0 < f.created_at AND f.created_at < 1000 RETURN fp").execute().await?;
+println!("{}", result);
+// Output:
+// Results
+// Project
+// Edge By Index Scan | [f:FOLLOW]
+// Node By Index Scan | (p:Person)
+{% endcapture %}
+
+{% include code_tabs.html id="relationship_explain_tabs" shell=shell_6 python=python_6 javascript=javascript_6 java=java_6 rust=rust_6 %}
+
+This can significantly improve the runtime of queries that traverse super nodes or when we want to start traverse from relationships.
+
+## Deleting an index for a node label
+
+For a node label, the index deletion syntax is:
+
+{% capture shell_7 %}
+GRAPH.QUERY DEMO_GRAPH "DROP INDEX ON :Person(age)"
+{% endcapture %}
+
+{% capture python_7 %}
+graph.query("DROP INDEX ON :Person(age)")
+{% endcapture %}
+
+{% capture javascript_7 %}
+await graph.query("DROP INDEX ON :Person(age)");
+{% endcapture %}
+
+{% capture java_7 %}
+graph.query("DROP INDEX ON :Person(age)");
+{% endcapture %}
+
+{% capture rust_7 %}
+graph.query("DROP INDEX ON :Person(age)").execute().await?;
+{% endcapture %}
+
+{% include code_tabs.html id="drop_node_index_tabs" shell=shell_7 python=python_7 javascript=javascript_7 java=java_7 rust=rust_7 %}
+
+## Deleting an index for a relationship type
+
+For a relationship type, the index deletion syntax is:
+
+{% capture shell_8 %}
+GRAPH.QUERY DEMO_GRAPH "DROP INDEX ON :FOLLOW(created_at)"
+{% endcapture %}
+
+{% capture python_8 %}
+graph.query("DROP INDEX ON :FOLLOW(created_at)")
+{% endcapture %}
+
+{% capture javascript_8 %}
+await graph.query("DROP INDEX ON :FOLLOW(created_at)");
+{% endcapture %}
+
+{% capture java_8 %}
+graph.query("DROP INDEX ON :FOLLOW(created_at)");
+{% endcapture %}
+
+{% capture rust_8 %}
+graph.query("DROP INDEX ON :FOLLOW(created_at)").execute().await?;
+{% endcapture %}
+
+{% include code_tabs.html id="drop_relationship_index_tabs" shell=shell_8 python=python_8 javascript=javascript_8 java=java_8 rust=rust_8 %}
+
+## Array Indices
+
+FalkorDB supports indexing on array properties containing scalar values (e.g., integers, floats, strings), enabling efficient lookups for elements within such arrays.
+
+Note: Complex types like nested arrays, maps, or vectors are not supported for indexing.
+
+The following example demonstrates how to index and search an array property:
+
+{% capture shell_9 %}
+# Create a node with an array property
+GRAPH.QUERY DEMO_GRAPH "CREATE (:Person {samples: [-21, 30.5, 0, 90, 3.14]})"
+
+# Create an index on the array property
+GRAPH.QUERY DEMO_GRAPH "CREATE INDEX FOR (p:Person) ON (p.samples)"
+
+# Use the index to search for nodes containing a specific value in the array
+GRAPH.QUERY DEMO_GRAPH "MATCH (p:Person) WHERE 90 IN p.samples RETURN p"
+{% endcapture %}
+
+{% capture python_9 %}
+# Create a node with an array property
+graph.query("CREATE (:Person {samples: [-21, 30.5, 0, 90, 3.14]})")
+
+# Create an index on the array property
+graph.query("CREATE INDEX FOR (p:Person) ON (p.samples)")
+
+# Use the index to search for nodes containing a specific value in the array
+result = graph.query("MATCH (p:Person) WHERE 90 IN p.samples RETURN p")
+{% endcapture %}
+
+{% capture javascript_9 %}
+// Create a node with an array property
+await graph.query("CREATE (:Person {samples: [-21, 30.5, 0, 90, 3.14]})");
+
+// Create an index on the array property
+await graph.query("CREATE INDEX FOR (p:Person) ON (p.samples)");
+
+// Use the index to search for nodes containing a specific value in the array
+const result = await graph.query("MATCH (p:Person) WHERE 90 IN p.samples RETURN p");
+{% endcapture %}
+
+{% capture java_9 %}
+// Create a node with an array property
+graph.query("CREATE (:Person {samples: [-21, 30.5, 0, 90, 3.14]})");
+
+// Create an index on the array property
+graph.query("CREATE INDEX FOR (p:Person) ON (p.samples)");
+
+// Use the index to search for nodes containing a specific value in the array
+ResultSet result = graph.query("MATCH (p:Person) WHERE 90 IN p.samples RETURN p");
+{% endcapture %}
+
+{% capture rust_9 %}
+// Create a node with an array property
+graph.query("CREATE (:Person {samples: [-21, 30.5, 0, 90, 3.14]})").execute().await?;
+
+// Create an index on the array property
+graph.query("CREATE INDEX FOR (p:Person) ON (p.samples)").execute().await?;
+
+// Use the index to search for nodes containing a specific value in the array
+let result = graph.query("MATCH (p:Person) WHERE 90 IN p.samples RETURN p").execute().await?;
+{% endcapture %}
+
+{% include code_tabs.html id="array_index_tabs" shell=shell_9 python=python_9 javascript=javascript_9 java=java_9 rust=rust_9 %}
+
+## Verifying Index Usage
+
+To verify that an index is being used by your query, use `GRAPH.EXPLAIN` before and after creating the index:
+
+{% capture shell_verify %}
+# Before creating the index
+GRAPH.EXPLAIN DEMO_GRAPH "MATCH (p:Person) WHERE p.age > 30 RETURN p"
+# Output shows: Label Scan | (p:Person)
+
+# Create the index
+GRAPH.QUERY DEMO_GRAPH "CREATE INDEX FOR (p:Person) ON (p.age)"
+
+# After creating the index
+GRAPH.EXPLAIN DEMO_GRAPH "MATCH (p:Person) WHERE p.age > 30 RETURN p"
+# Output now shows: Index Scan | (p:Person)
+{% endcapture %}
+
+{% capture python_verify %}
+# Before creating the index
+result = graph.explain("MATCH (p:Person) WHERE p.age > 30 RETURN p")
+print(result) # Shows: Label Scan | (p:Person)
+
+# Create the index
+graph.query("CREATE INDEX FOR (p:Person) ON (p.age)")
+
+# After creating the index
+result = graph.explain("MATCH (p:Person) WHERE p.age > 30 RETURN p")
+print(result) # Now shows: Index Scan | (p:Person)
+{% endcapture %}
+
+{% capture javascript_verify %}
+// Before creating the index
+let result = await graph.explain("MATCH (p:Person) WHERE p.age > 30 RETURN p");
+console.log(result); // Shows: Label Scan | (p:Person)
+
+// Create the index
+await graph.query("CREATE INDEX FOR (p:Person) ON (p.age)");
+
+// After creating the index
+result = await graph.explain("MATCH (p:Person) WHERE p.age > 30 RETURN p");
+console.log(result); // Now shows: Index Scan | (p:Person)
+{% endcapture %}
+
+{% capture java_verify %}
+// Before creating the index
+String result = graph.explain("MATCH (p:Person) WHERE p.age > 30 RETURN p");
+System.out.println(result); // Shows: Label Scan | (p:Person)
+
+// Create the index
+graph.query("CREATE INDEX FOR (p:Person) ON (p.age)");
+
+// After creating the index
+result = graph.explain("MATCH (p:Person) WHERE p.age > 30 RETURN p");
+System.out.println(result); // Now shows: Index Scan | (p:Person)
+{% endcapture %}
+
+{% capture rust_verify %}
+// Before creating the index
+let result = graph.explain("MATCH (p:Person) WHERE p.age > 30 RETURN p").execute().await?;
+println!("{}", result); // Shows: Label Scan | (p:Person)
+
+// Create the index
+graph.query("CREATE INDEX FOR (p:Person) ON (p.age)").execute().await?;
+
+// After creating the index
+let result = graph.explain("MATCH (p:Person) WHERE p.age > 30 RETURN p").execute().await?;
+println!("{}", result); // Now shows: Index Scan | (p:Person)
+{% endcapture %}
+
+{% include code_tabs.html id="verify_index_tabs" shell=shell_verify python=python_verify javascript=javascript_verify java=java_verify rust=rust_verify %}
+
+## Index Management
+
+### Listing Existing Indexes
+
+To view all indexes in your graph, use the `db.indexes()` procedure:
+
+```cypher
+CALL db.indexes()
+```
+
+This returns information about all indexes including their type (RANGE), entity type (node/relationship), labels, and properties.
+
+## Performance Tradeoffs and Best Practices
+
+### When to Use Range Indexes
+
+Range indexes are ideal for:
+- **Filtering by specific values**: Queries with equality filters (e.g., `WHERE p.name = 'Alice'`)
+- **Range queries**: Numeric or string comparisons (e.g., `WHERE p.age > 30`, `WHERE p.name >= 'A' AND p.name < 'B'`)
+- **Geospatial queries**: Finding entities within a certain distance
+- **Array membership**: Checking if a value exists in an array property
+
+### Performance Considerations
+
+**Benefits:**
+- Dramatically improves query performance for filtered searches
+- Reduces the number of nodes/relationships that need to be scanned
+- Enables efficient range scans and point lookups
+
+**Costs:**
+- **Write overhead**: Every insert or update to an indexed property requires updating the index
+- **Storage**: Indexes consume additional memory and disk space
+- **Maintenance**: Index structures need to be maintained during graph modifications
+
+**Recommendations:**
+- Index properties that are frequently used in `WHERE` clauses
+- Avoid indexing properties that are rarely queried or have high write frequency
+- For properties with very few distinct values (low cardinality), indexes may not provide significant benefits
+- Monitor query performance with `GRAPH.PROFILE` to validate index effectiveness
+
+### Example: Profiling Index Performance
+
+```cypher
+# Profile query to see actual execution metrics
+GRAPH.PROFILE DEMO_GRAPH "MATCH (p:Person) WHERE p.age > 30 RETURN p"
+```
+
+This shows detailed timing information and confirms whether the index was used.
diff --git a/cypher/indexing/vector-index.md b/cypher/indexing/vector-index.md
new file mode 100644
index 00000000..e11784cc
--- /dev/null
+++ b/cypher/indexing/vector-index.md
@@ -0,0 +1,421 @@
+---
+title: "Vector Index"
+nav_order: 3
+description: >
+ FalkorDB supports vector indexes for similarity search on vector embeddings, essential for AI and machine learning applications.
+parent: "Indexing"
+grand_parent: "Cypher Language"
+---
+
+# Vector indexing
+
+With the introduction of the `vector` data-type a new type of index was introduced.
+A vector index is a dedicated index for indexing and searching through vectors.
+
+To create this type of index use the following syntax:
+
+```cypher
+CREATE VECTOR INDEX FOR ON OPTIONS
+```
+
+The options are:
+```
+{
+ dimension: INT, // Required, length of the vector to be indexed
+ similarityFunction: STRING, // Required, currently only euclidean or cosine are allowed
+ M: INT, // Optional, maximum number of outgoing edges per node. default 16
+ efConstruction: INT, // Optional, number of candidates during construction. default 200
+ efRuntime: INT // Optional, number of candidates during search. default 10
+}
+```
+
+For example, to create a vector index over all `Product` nodes `description` attribute
+use the following syntax:
+
+{% capture shell_19 %}
+CREATE VECTOR INDEX FOR (p:Product) ON (p.description) OPTIONS {dimension:128, similarityFunction:'euclidean'}
+{% endcapture %}
+
+{% capture python_19 %}
+graph.query("CREATE VECTOR INDEX FOR (p:Product) ON (p.description) OPTIONS {dimension:128, similarityFunction:'euclidean'}")
+{% endcapture %}
+
+{% capture javascript_19 %}
+await graph.query("CREATE VECTOR INDEX FOR (p:Product) ON (p.description) OPTIONS {dimension:128, similarityFunction:'euclidean'}");
+{% endcapture %}
+
+{% capture java_19 %}
+graph.query("CREATE VECTOR INDEX FOR (p:Product) ON (p.description) OPTIONS {dimension:128, similarityFunction:'euclidean'}");
+{% endcapture %}
+
+{% capture rust_19 %}
+graph.query("CREATE VECTOR INDEX FOR (p:Product) ON (p.description) OPTIONS {dimension:128, similarityFunction:'euclidean'}").execute().await?;
+{% endcapture %}
+
+{% include code_tabs.html id="vector_create_node_tabs" shell=shell_19 python=python_19 javascript=javascript_19 java=java_19 rust=rust_19 %}
+
+Similarly to create a vector index over all `Call` relationships `summary` attribute
+use the following syntax:
+
+{% capture shell_20 %}
+CREATE VECTOR INDEX FOR ()-[e:Call]->() ON (e.summary) OPTIONS {dimension:128, similarityFunction:'euclidean'}
+{% endcapture %}
+
+{% capture python_20 %}
+graph.query("CREATE VECTOR INDEX FOR ()-[e:Call]->() ON (e.summary) OPTIONS {dimension:128, similarityFunction:'euclidean'}")
+{% endcapture %}
+
+{% capture javascript_20 %}
+await graph.query("CREATE VECTOR INDEX FOR ()-[e:Call]->() ON (e.summary) OPTIONS {dimension:128, similarityFunction:'euclidean'}");
+{% endcapture %}
+
+{% capture java_20 %}
+graph.query("CREATE VECTOR INDEX FOR ()-[e:Call]->() ON (e.summary) OPTIONS {dimension:128, similarityFunction:'euclidean'}");
+{% endcapture %}
+
+{% capture rust_20 %}
+graph.query("CREATE VECTOR INDEX FOR ()-[e:Call]->() ON (e.summary) OPTIONS {dimension:128, similarityFunction:'euclidean'}").execute().await?;
+{% endcapture %}
+
+{% include code_tabs.html id="vector_create_relation_tabs" shell=shell_20 python=python_20 javascript=javascript_20 java=java_20 rust=rust_20 %}
+
+**Important**: When creating a vector index, both the vector dimension and similarity function must be provided. Currently, the only supported similarity functions are 'euclidean' or 'cosine'.
+
+## Understanding Vector Index Parameters
+
+### Required Parameters
+
+- **dimension**: The length of the vectors to be indexed. Must match the dimensionality of your embeddings (e.g., 128, 384, 768, 1536).
+- **similarityFunction**: The distance metric used for similarity search:
+ - `euclidean`: Euclidean distance (L2 norm). Best for embeddings where magnitude matters.
+ - `cosine`: Cosine similarity. Best for normalized embeddings where direction matters more than magnitude.
+
+### Optional Parameters
+
+These parameters control the HNSW (Hierarchical Navigable Small World) index structure:
+
+- **M** (default: 16): Maximum number of connections per node in the graph
+ - Higher values improve recall but increase memory usage and build time
+ - Recommended range: 12-48
+ - Use 16-32 for most applications
+
+- **efConstruction** (default: 200): Number of candidates evaluated during index construction
+ - Higher values improve index quality but slow down indexing
+ - Recommended range: 100-400
+ - Use 200-300 for balanced quality/speed
+
+- **efRuntime** (default: 10): Number of candidates evaluated during search
+ - Higher values improve recall but slow down queries
+ - Can be adjusted per-query for speed/accuracy tradeoffs
+ - Recommended: Start with 10, increase if recall is insufficient
+
+## Inserting vectors
+
+To create a new vector use the [vecf32](/cypher/functions#vector-functions) function
+as follows:
+
+{% capture shell_21 %}
+CREATE (p: Product {description: vecf32([2.1, 0.82, 1.3])})
+{% endcapture %}
+
+{% capture python_21 %}
+graph.query("CREATE (p: Product {description: vecf32([2.1, 0.82, 1.3])})")
+{% endcapture %}
+
+{% capture javascript_21 %}
+await graph.query("CREATE (p: Product {description: vecf32([2.1, 0.82, 1.3])})");
+{% endcapture %}
+
+{% capture java_21 %}
+graph.query("CREATE (p: Product {description: vecf32([2.1, 0.82, 1.3])})");
+{% endcapture %}
+
+{% capture rust_21 %}
+graph.query("CREATE (p: Product {description: vecf32([2.1, 0.82, 1.3])})").execute().await?;
+{% endcapture %}
+
+{% include code_tabs.html id="vector_insert_tabs" shell=shell_21 python=python_21 javascript=javascript_21 java=java_21 rust=rust_21 %}
+
+The above query creates a new `Product` node with a `description` attribute containing a vector.
+
+## Query vector index
+
+Vector indices are used to search for similar vectors to a given query vector
+using the similarity function as a measure of "distance".
+
+To query the index use either `db.idx.vector.queryNodes` for node retrieval or
+`db.idx.vector.queryRelationships` for relationships.
+
+```cypher
+CALL db.idx.vector.queryNodes(
+ label: STRING,
+ attribute: STRING,
+ k: INTEGER,
+ query: VECTOR
+) YIELD node, score
+```
+
+```cypher
+CALL db.idx.vector.queryRelationships(
+ relationshipType: STRING,
+ attribute: STRING,
+ k: INTEGER,
+ query: VECTOR
+) YIELD relationship, score
+```
+
+To query up to 10 similar `Product` descriptions to a given query description vector
+issue the following procedure call:
+
+{% capture shell_22 %}
+CALL db.idx.vector.queryNodes(
+ 'Product',
+ 'description',
+ 10,
+ vecf32(),
+ ) YIELD node
+{% endcapture %}
+
+{% capture python_22 %}
+result = graph.query("CALL db.idx.vector.queryNodes('Product', 'description', 10, vecf32()) YIELD node")
+{% endcapture %}
+
+{% capture javascript_22 %}
+const result = await graph.query("CALL db.idx.vector.queryNodes('Product', 'description', 10, vecf32()) YIELD node");
+{% endcapture %}
+
+{% capture java_22 %}
+ResultSet result = graph.query("CALL db.idx.vector.queryNodes('Product', 'description', 10, vecf32()) YIELD node");
+{% endcapture %}
+
+{% capture rust_22 %}
+let result = graph.query("CALL db.idx.vector.queryNodes('Product', 'description', 10, vecf32()) YIELD node").execute().await?;
+{% endcapture %}
+
+{% include code_tabs.html id="vector_query_tabs" shell=shell_22 python=python_22 javascript=javascript_22 java=java_22 rust=rust_22 %}
+
+The procedure can yield both the indexed entity assigned to the found similar vector
+in addition to a similarity score of that entity.
+
+## Deleting a vector index
+
+To remove a vector index, simply issue the `drop index` command as follows:
+
+```cypher
+DROP VECTOR INDEX FOR ()
+```
+
+For example, to drop the vector index over Product description, invoke:
+
+{% capture shell_23 %}
+DROP VECTOR INDEX FOR (p:Product) ON (p.description)
+{% endcapture %}
+
+{% capture python_23 %}
+graph.query("DROP VECTOR INDEX FOR (p:Product) ON (p.description)")
+{% endcapture %}
+
+{% capture javascript_23 %}
+await graph.query("DROP VECTOR INDEX FOR (p:Product) ON (p.description)");
+{% endcapture %}
+
+{% capture java_23 %}
+graph.query("DROP VECTOR INDEX FOR (p:Product) ON (p.description)");
+{% endcapture %}
+
+{% capture rust_23 %}
+graph.query("DROP VECTOR INDEX FOR (p:Product) ON (p.description)").execute().await?;
+{% endcapture %}
+
+{% include code_tabs.html id="vector_drop_tabs" shell=shell_23 python=python_23 javascript=javascript_23 java=java_23 rust=rust_23 %}
+
+## Index Management
+
+### Listing Vector Indexes
+
+To view all indexes (including vector) in your graph, use:
+
+```cypher
+CALL db.indexes()
+```
+
+Vector indexes are marked with type `VECTOR` and show the dimension and similarity function in the options field.
+
+## Verifying Vector Index Usage
+
+To verify that a vector index is being used, examine the query execution plan:
+
+{% capture shell_vec_verify %}
+# Query using vector index
+GRAPH.EXPLAIN DEMO_GRAPH "CALL db.idx.vector.queryNodes('Product', 'description', 10, vecf32([2.1, 0.82, 1.3])) YIELD node RETURN node"
+# Output shows: ProcedureCall | db.idx.vector.queryNodes
+{% endcapture %}
+
+{% capture python_vec_verify %}
+# Query using vector index
+query_vector = [2.1, 0.82, 1.3]
+result = graph.explain(f"CALL db.idx.vector.queryNodes('Product', 'description', 10, vecf32({query_vector})) YIELD node RETURN node")
+print(result)
+# Output shows: ProcedureCall | db.idx.vector.queryNodes
+{% endcapture %}
+
+{% capture javascript_vec_verify %}
+// Query using vector index
+const queryVector = [2.1, 0.82, 1.3];
+const result = await graph.explain(`CALL db.idx.vector.queryNodes('Product', 'description', 10, vecf32([${queryVector}])) YIELD node RETURN node`);
+console.log(result);
+// Output shows: ProcedureCall | db.idx.vector.queryNodes
+{% endcapture %}
+
+{% capture java_vec_verify %}
+// Query using vector index
+float[] queryVector = {2.1f, 0.82f, 1.3f};
+String result = graph.explain("CALL db.idx.vector.queryNodes('Product', 'description', 10, vecf32([2.1, 0.82, 1.3])) YIELD node RETURN node");
+System.out.println(result);
+// Output shows: ProcedureCall | db.idx.vector.queryNodes
+{% endcapture %}
+
+{% capture rust_vec_verify %}
+// Query using vector index
+let result = graph.explain("CALL db.idx.vector.queryNodes('Product', 'description', 10, vecf32([2.1, 0.82, 1.3])) YIELD node RETURN node").execute().await?;
+println!("{}", result);
+// Output shows: ProcedureCall | db.idx.vector.queryNodes
+{% endcapture %}
+
+{% include code_tabs.html id="vector_verify_tabs" shell=shell_vec_verify python=python_vec_verify javascript=javascript_vec_verify java=java_vec_verify rust=rust_vec_verify %}
+
+## Performance Tradeoffs and Best Practices
+
+### When to Use Vector Indexes
+
+Vector indexes are essential for:
+- **Semantic search**: Finding similar items based on meaning, not just keywords
+- **Recommendation systems**: Discovering similar products, content, or users
+- **RAG (Retrieval Augmented Generation)**: Retrieving relevant context for LLMs
+- **Duplicate detection**: Finding near-duplicate items based on embeddings
+- **Image/audio similarity**: When using vision or audio embedding models
+
+### Performance Considerations
+
+**Benefits:**
+- Enables efficient approximate nearest neighbor (ANN) search
+- Scales to millions of vectors with sub-linear query time
+- Supports both node and relationship vectors
+
+**Costs:**
+- **Memory usage**: Vector indexes are memory-intensive
+ - A 1M vector index with 768 dimensions (float32) requires ~3GB of memory
+ - Formula: `vectors Γ dimensions Γ 4 bytes + HNSW overhead (~20%)`
+- **Build time**: Index construction can be slow for large datasets
+- **Approximate results**: Returns approximate (not exact) nearest neighbors
+- **No support for filtering**: Vector queries don't combine well with property filters
+
+**Recommendations:**
+- Choose appropriate vector dimensions (balance between quality and cost)
+- Use cosine similarity for normalized embeddings (e.g., from OpenAI, Sentence Transformers)
+- Use euclidean distance for unnormalized data
+- Tune M and efConstruction based on your accuracy requirements
+- Consider batch indexing for large datasets
+- Monitor memory usage carefully
+
+### Similarity Function Tradeoffs
+
+**Cosine Similarity:**
+- Best for: Text embeddings, normalized vectors
+- Measures: Angular distance between vectors
+- Range: -1 to 1 (1 = identical direction)
+- Use when: Vector magnitude is not meaningful
+
+**Euclidean Distance:**
+- Best for: Unnormalized data, physical measurements
+- Measures: Straight-line distance between vectors
+- Range: 0 to β (0 = identical)
+- Use when: Both direction and magnitude matter
+
+### Example: Realistic Vector Search
+
+{% capture shell_vec_example %}
+# Create vector index for product embeddings
+GRAPH.QUERY DEMO_GRAPH "CREATE VECTOR INDEX FOR (p:Product) ON (p.embedding) OPTIONS {dimension:768, similarityFunction:'cosine', M:32, efConstruction:200}"
+
+# Insert products with embeddings (embeddings would come from your model)
+GRAPH.QUERY DEMO_GRAPH "CREATE (p:Product {name: 'Laptop', embedding: vecf32([0.1, 0.2, ...])})"
+
+# Search for similar products
+GRAPH.QUERY DEMO_GRAPH "CALL db.idx.vector.queryNodes('Product', 'embedding', 5, vecf32([0.15, 0.18, ...])) YIELD node, score RETURN node.name, score ORDER BY score DESC"
+{% endcapture %}
+
+{% capture python_vec_example %}
+# Create vector index for product embeddings
+graph.query("CREATE VECTOR INDEX FOR (p:Product) ON (p.embedding) OPTIONS {dimension:768, similarityFunction:'cosine', M:32, efConstruction:200}")
+
+# Insert products with embeddings (embeddings would come from your model)
+embedding = model.encode("laptop computer") # Your embedding model
+graph.query(f"CREATE (p:Product {name: 'Laptop', embedding: vecf32({embedding.tolist()})})")
+
+# Search for similar products
+query_embedding = model.encode("notebook pc")
+result = graph.query(f"CALL db.idx.vector.queryNodes('Product', 'embedding', 5, vecf32({query_embedding.tolist()})) YIELD node, score RETURN node.name, score ORDER BY score DESC")
+for record in result.result_set:
+ print(f"Product: {record[0]}, Similarity: {record[1]}")
+{% endcapture %}
+
+{% capture javascript_vec_example %}
+// Create vector index for product embeddings
+await graph.query("CREATE VECTOR INDEX FOR (p:Product) ON (p.embedding) OPTIONS {dimension:768, similarityFunction:'cosine', M:32, efConstruction:200}");
+
+// Insert products with embeddings (embeddings would come from your model)
+const embedding = await model.encode("laptop computer"); // Your embedding model
+await graph.query(`CREATE (p:Product {name: 'Laptop', embedding: vecf32([${embedding}])})`);
+
+// Search for similar products
+const queryEmbedding = await model.encode("notebook pc");
+const result = await graph.query(`CALL db.idx.vector.queryNodes('Product', 'embedding', 5, vecf32([${queryEmbedding}])) YIELD node, score RETURN node.name, score ORDER BY score DESC`);
+for (const record of result.data) {
+ console.log(`Product: ${record['node.name']}, Similarity: ${record['score']}`);
+}
+{% endcapture %}
+
+{% capture java_vec_example %}
+// Create vector index for product embeddings
+graph.query("CREATE VECTOR INDEX FOR (p:Product) ON (p.embedding) OPTIONS {dimension:768, similarityFunction:'cosine', M:32, efConstruction:200}");
+
+// Insert products with embeddings (embeddings would come from your model)
+float[] embedding = model.encode("laptop computer"); // Your embedding model
+graph.query(String.format("CREATE (p:Product {name: 'Laptop', embedding: vecf32(%s)})", Arrays.toString(embedding)));
+
+// Search for similar products
+float[] queryEmbedding = model.encode("notebook pc");
+ResultSet result = graph.query(String.format("CALL db.idx.vector.queryNodes('Product', 'embedding', 5, vecf32(%s)) YIELD node, score RETURN node.name, score ORDER BY score DESC", Arrays.toString(queryEmbedding)));
+for (Record record : result) {
+ System.out.printf("Product: %s, Similarity: %s%n", record.get("node.name"), record.get("score"));
+}
+{% endcapture %}
+
+{% capture rust_vec_example %}
+// Create vector index for product embeddings
+graph.query("CREATE VECTOR INDEX FOR (p:Product) ON (p.embedding) OPTIONS {dimension:768, similarityFunction:'cosine', M:32, efConstruction:200}").execute().await?;
+
+// Insert products with embeddings (embeddings would come from your model)
+let embedding = model.encode("laptop computer"); // Your embedding model
+graph.query(&format!("CREATE (p:Product {name: 'Laptop', embedding: vecf32({:?})})", embedding)).execute().await?;
+
+// Search for similar products
+let query_embedding = model.encode("notebook pc");
+let result = graph.query(&format!("CALL db.idx.vector.queryNodes('Product', 'embedding', 5, vecf32({:?})) YIELD node, score RETURN node.name, score ORDER BY score DESC", query_embedding)).execute().await?;
+for record in result.data() {
+ println!("Product: {}, Similarity: {}", record["node.name"], record["score"]);
+}
+{% endcapture %}
+
+{% include code_tabs.html id="vector_example_tabs" shell=shell_vec_example python=python_vec_example javascript=javascript_vec_example java=java_vec_example rust=rust_vec_example %}
+
+### Troubleshooting
+
+**Common Issues:**
+
+1. **Dimension mismatch**: Ensure all vectors have the same dimension as specified in the index
+2. **Wrong similarity function**: Use cosine for normalized vectors, euclidean for unnormalized
+3. **Poor recall**: Increase efRuntime or efConstruction parameters
+4. **Slow queries**: Decrease efRuntime or reduce k (number of results)
+5. **High memory usage**: Reduce M parameter or use lower-dimensional embeddings
diff --git a/cypher/match.md b/cypher/match.md
index 588c8fe3..6976a83d 100644
--- a/cypher/match.md
+++ b/cypher/match.md
@@ -8,16 +8,19 @@ parent: "Cypher Language"
# MATCH
-Match describes the relationship between queried entities, using ascii art to represent pattern(s) to match against.
+The `MATCH` clause describes the relationship between queried entities using ASCII art to represent pattern(s) to match against.
-Nodes are represented by parentheses `()`,
-and Relationships are represented by brackets `[]`.
+**Syntax Overview:**
+- Nodes are represented by parentheses `()`
+- Relationships are represented by brackets `[]`
+- Each graph entity (node/relationship) can contain an alias, a label/relationship type, and filters, but all are optional
-Each graph entity node/relationship can contain an alias and a label/relationship type, but both can be left empty if necessary.
+**Entity Structure:** `alias:label {filters}`
-Entity structure: `alias:label {filters}`.
-
-Alias, label/relationship type, and filters are all optional.
+Where:
+- `alias` - Optional variable name to reference the entity
+- `label` - Optional label for nodes or type for relationships
+- `{filters}` - Optional property filters
Example:
@@ -35,10 +38,9 @@ Example:
`Movie` destination node is of "type" movie.
-`{title:"straight outta compton"}` requires the node's title attribute to equal "straight outta compton".
+`{title:"straight outta compton"}` filters for nodes where the title property equals "straight outta compton".
-In this example, we're interested in actor entities which have the relation "act" with **the** entity representing the
-"straight outta compton" movie.
+In this example, we're querying for actor entities that have an "ACT" relationship with the movie entity "straight outta compton".
It is possible to describe broader relationships by composing a multi-hop query such as:
diff --git a/cypher/procedures.md b/cypher/procedures.md
index ebd4e80a..0d2f9aba 100644
--- a/cypher/procedures.md
+++ b/cypher/procedures.md
@@ -8,30 +8,41 @@ parent: "Cypher Language"
# Procedures
-Procedures are invoked using the syntax:
+Procedures are functions that can be called from within Cypher queries using the `CALL` syntax.
+
+## Syntax
+
+Basic procedure call:
```sh
GRAPH.QUERY social "CALL db.labels()"
```
-Or the variant:
+With explicit `YIELD` to select specific return values:
```sh
GRAPH.QUERY social "CALL db.labels() YIELD label"
```
-YIELD modifiers are only required if explicitly specified; by default the value in the 'Yields' column will be emitted automatically.
+**Note:** The `YIELD` clause is optional. When omitted, all values listed in the 'Yields' column are returned automatically.
+
+## Available Procedures
| Procedure | Arguments | Yields | Description |
| ------- | :------- | :------- | :----------- |
| db.labels | none | `label` | Yields all node labels in the graph. |
| db.relationshipTypes | none | `relationshipType` | Yields all relationship types in the graph. |
| db.propertyKeys | none | `propertyKey` | Yields all property keys in the graph. |
+| db.meta.stats | none | `labels`, `relTypes`, `relCount`, `nodeCount`, `labelCount`, `relTypeCount`, `propertyKeyCount` | Yield comprehensive graph statistics including maps of labels and relationship types with their counts, total node/relationship counts, and schema metadata counts. |
| db.indexes | none | `label`, `properties`, `types`, `options`, `language`, `stopwords`, `entitytype`, `status`, `info` | Yield all indexes in the graph, denoting whether they are of the type of exact-match ("RANGE"), full-text ("FULLTEXT") or vector ("VECTOR") and which label and properties each covers and whether they are indexing node or relationship attributes. |
| db.constraints | none | `type`, `label`, `properties`, `entitytype`, `status` | Yield all constraints in the graph, denoting constraint type (UNIQIE/MANDATORY), which label/relationship-type and properties each enforces. |
| db.idx.fulltext.createNodeIndex | `label`, `property` [, `property` ...] | none | Builds a full-text searchable index on a label and the 1 or more specified properties. |
| db.idx.fulltext.drop | `label` | none | Deletes the full-text index associated with the given label. |
| db.idx.fulltext.queryNodes | `label`, `string` | `node`, `score` | Retrieve all nodes that contain the specified string in the full-text indexes on the given label. |
+| db.idx.fulltext.queryRelationships | `relationshipType`, `string` | `relationship`, `score` | Retrieve all relationships that contain the specified string in the full-text indexes on the given relationship type. See [Full-Text Indexing](/cypher/indexing/fulltext-index) for details. |
+| db.idx.vector.queryNodes | `label`, `attribute`, `k`, `query` | `node`, `score` | Retrieve up to k nodes with vectors most similar to the query vector using the specified label and attribute. See [Vector Indexing](/cypher/indexing/vector-index) for details. |
+| db.idx.vector.queryRelationships | `relationshipType`, `attribute`, `k`, `query` | `relationship`, `score` | Retrieve up to k relationships with vectors most similar to the query vector using the specified relationship type and attribute. See [Vector Indexing](/cypher/indexing/vector-index) for details. |
| algo.pageRank | `label`, `relationship-type` | `node`, `score` | Runs the pagerank algorithm over nodes of given label, considering only edges of given relationship type. |
-| [algo.BFS](#BFS) | `source-node`, `max-level`, `relationship-type` | `nodes`, `edges` | Performs BFS to find all nodes connected to the source. A `max level` of 0 indicates unlimited and a non-NULL `relationship-type` defines the relationship type that may be traversed. |
+| algo.BFS | `source-node`, `max-level`, `relationship-type` | `nodes`, `edges` | Performs BFS to find all nodes connected to the source. A `max level` of 0 indicates unlimited and a non-NULL `relationship-type` defines the relationship type that may be traversed. See [BFS Algorithm](/algorithms/bfs) for details. |
+| algo.MSF | `config` | `src`, `dest`, `weight`, `relationshipType` | Computes the Minimum Spanning Forest of the graph. See [MSF Algorithm](/algorithms/msf) for details. |
| dbms.procedures() | none | `name`, `mode` | List all procedures in the DBMS, yields for every procedure its name and mode (read/write). |
diff --git a/cypher/return.md b/cypher/return.md
index 30f9e1be..9543e3d8 100644
--- a/cypher/return.md
+++ b/cypher/return.md
@@ -8,51 +8,57 @@ parent: "Cypher Language"
# RETURN
-In its simple form, Return defines which properties the returned result-set will contain.
+The `RETURN` clause defines which properties and values the result-set will contain.
-Its structure is a list of `alias.property` separated by commas.
+## Basic Usage
-For convenience, it's possible to specify the alias only when you're interested in every attribute an entity possesses,
-and don't want to specify each attribute individually. For example:
+The basic structure is a comma-separated list of `alias.property` expressions:
+
+```sh
+RETURN person.name, person.age
+```
+
+For convenience, you can specify just the alias to return all properties of an entity:
```sh
RETURN movie.title, actor
```
-Use the DISTINCT keyword to remove duplications within the result-set:
+## Removing Duplicates
+
+Use the `DISTINCT` keyword to remove duplicate values from the result-set:
```sh
RETURN DISTINCT friend_of_friend.name
```
-In the above example, suppose we have two friends, Joe and Miesha,
-and both know Dominick.
+For example, if you have two friends (Joe and Miesha) who both know Dominick, `DISTINCT` ensures that Dominick appears only once in the final result set.
-DISTINCT will make sure Dominick will only appear once
-in the final result set.
+## Aggregations
-Return can also be used to aggregate data, similar to group by in SQL.
+The `RETURN` clause can also aggregate data, similar to SQL's GROUP BY functionality.
-Once an aggregation function is added to the return
-list, all other "none" aggregated values are considered as group keys, for example:
+When an aggregation function is used in the RETURN list, all non-aggregated values become implicit grouping keys:
```sh
RETURN movie.title, MAX(actor.age), MIN(actor.age)
```
-Here we group data by movie title and for each movie, and we find its youngest and oldest actor age.
+This query groups data by movie title and, for each movie, returns the youngest and oldest actor ages.
-## Aggregations
+### Supported Aggregation Functions
+
+| Function | Description |
+|----------|-------------|
+| `avg` | Calculate average of numeric values |
+| `collect` | Collect values into a list |
+| `count` | Count number of values |
+| `max` | Find maximum value |
+| `min` | Find minimum value |
+| `percentileCont` | Calculate continuous percentile |
+| `percentileDisc` | Calculate discrete percentile |
+| `stDev` | Calculate standard deviation |
+| `sum` | Calculate sum of numeric values |
-Supported aggregation functions include:
-
-* `avg`
-* `collect`
-* `count`
-* `max`
-* `min`
-* `percentileCont`
-* `percentileDisc`
-* `stDev`
-* `sum`
\ No newline at end of file
+For detailed information on aggregation functions, see the [Functions documentation](/cypher/functions#aggregating-functions).
\ No newline at end of file
diff --git a/cypher/set.md b/cypher/set.md
index 294d0965..6b7256a8 100644
--- a/cypher/set.md
+++ b/cypher/set.md
@@ -8,15 +8,19 @@ parent: "Cypher Language"
# SET
-SET is used to create or update properties on nodes and relationships.
+The `SET` clause is used to create or update properties on nodes and relationships.
-To set a property on a node, use `SET`.
+## Setting a Single Property
+
+To set a property on a node:
```sh
GRAPH.QUERY DEMO_GRAPH "MATCH (n { name: 'Jim' }) SET n.name = 'Bob'"
```
-If you want to set multiple properties in one go, simply separate them with a comma to set multiple properties using a single SET clause.
+## Setting Multiple Properties
+
+You can set multiple properties in a single `SET` clause by separating them with commas:
```sh
GRAPH.QUERY DEMO_GRAPH
@@ -24,7 +28,13 @@ GRAPH.QUERY DEMO_GRAPH
SET n.age = 33, n.name = 'Bob'"
```
-The same can be accomplished by setting the graph entity variable to a map:
+## Setting Properties from a Map
+
+You can set properties using a map. There are two operators with different behaviors:
+
+### Replace All Properties (`=`)
+
+Replaces **all** existing properties with the map properties:
```sh
GRAPH.QUERY DEMO_GRAPH
@@ -32,9 +42,23 @@ GRAPH.QUERY DEMO_GRAPH
SET n = {age: 33, name: 'Bob'}"
```
-Using `=` in this way replaces all of the entity's previous properties, while `+=` will only set the properties it explicitly mentions.
+**Result:** The node will have only the properties `age` and `name`. Any other existing properties are removed.
-In the same way, the full property set of a graph entity can be assigned or merged:
+### Merge Properties (`+=`)
+
+Updates only the specified properties while keeping other existing properties:
+
+```sh
+GRAPH.QUERY DEMO_GRAPH
+"MATCH (n { name: 'Jim', age:32 })
+SET n += {age: 33}"
+```
+
+**Result:** The node's `age` is updated to 33, but `name` and any other properties remain unchanged.
+
+## Copying Properties Between Entities
+
+You can copy all properties from one entity to another:
```sh
GRAPH.QUERY DEMO_GRAPH
@@ -42,10 +66,14 @@ GRAPH.QUERY DEMO_GRAPH
SET jim = pam"
```
-After executing this query, the `jim` node will have the same property set as the `pam` node.
+After executing this query, the `jim` node will have exactly the same properties as the `pam` node (all of Jim's original properties are replaced).
+
+## Removing Properties
-To remove a node's property, simply set property value to NULL.
+To remove a property, set its value to `NULL`:
```sh
GRAPH.QUERY DEMO_GRAPH "MATCH (n { name: 'Jim' }) SET n.name = NULL"
-```
\ No newline at end of file
+```
+
+This removes the `name` property from the node entirely.
\ No newline at end of file
diff --git a/cypher/unwind.md b/cypher/unwind.md
index 58557c50..c474e29f 100644
--- a/cypher/unwind.md
+++ b/cypher/unwind.md
@@ -8,16 +8,61 @@ parent: "Cypher Language"
# UNWIND
-The UNWIND clause breaks down a given list into a sequence of records; each contains a single element in the list.
+The `UNWIND` clause transforms a list into individual rows, creating one row for each element in the list.
-The order of the records preserves the original list order.
+## Behavior
+
+- Each element in the list becomes a separate row
+- The order of rows preserves the original list order
+- Useful for processing lists, creating multiple entities, or parameter expansion
+
+## Basic Example
+
+Create a node with an array property:
+
+```sh
+GRAPH.QUERY DEMO_GRAPH "CREATE (p {array:[1,2,3]})"
+```
+
+Unwind the array into individual rows:
+
+```sh
+GRAPH.QUERY DEMO_GRAPH "MATCH (p) UNWIND p.array AS y RETURN y"
+```
+
+**Result:**
+```
+y
+1
+2
+3
+```
+
+## Practical Examples
+
+### Create Multiple Nodes from a List
+
+```sh
+GRAPH.QUERY DEMO_GRAPH
+"UNWIND ['Alice', 'Bob', 'Charlie'] AS name
+CREATE (:Person {name: name})"
+```
+
+### Process Nested Data
```sh
GRAPH.QUERY DEMO_GRAPH
-"CREATE (p {array:[1,2,3]})"
+"WITH [{name: 'Alice', age: 30}, {name: 'Bob', age: 25}] AS people
+UNWIND people AS person
+CREATE (:Person {name: person.name, age: person.age})"
```
+### Combine with Other Clauses
+
```sh
GRAPH.QUERY DEMO_GRAPH
-"MATCH (p) UNWIND p.array AS y RETURN y"
+"MATCH (p:Person)
+WITH collect(p.name) AS names
+UNWIND names AS name
+RETURN name ORDER BY name"
```
\ No newline at end of file
diff --git a/cypher/where.md b/cypher/where.md
index a2f8fc97..645675d8 100644
--- a/cypher/where.md
+++ b/cypher/where.md
@@ -8,26 +8,30 @@ parent: "Cypher Language"
# WHERE
-This clause is not mandatory, but if you want to filter results, you can specify your predicates here.
+The `WHERE` clause is optional and is used to filter results based on predicates (conditions).
-Supported operations:
+## Supported Comparison Operators
-* `=`
-* `<>`
-* `<`
-* `<=`
-* `>`
-* `>=`
-* `CONTAINS`
-* `ENDS WITH`
-* `IN`
-* `STARTS WITH`
+| Operator | Description |
+|----------|-------------|
+| `=` | Equal to |
+| `<>` | Not equal to |
+| `<` | Less than |
+| `<=` | Less than or equal to |
+| `>` | Greater than |
+| `>=` | Greater than or equal to |
+| `CONTAINS` | String contains substring |
+| `ENDS WITH` | String ends with substring |
+| `IN` | Value is in list |
+| `STARTS WITH` | String starts with substring |
-Predicates can be combined using AND / OR / NOT.
+## Combining Predicates
-Be sure to wrap predicates within parentheses to control precedence.
+Predicates can be combined using the logical operators `AND`, `OR`, and `NOT`.
-Examples:
+Use parentheses to control precedence when combining multiple predicates.
+
+### Examples:
```sql
WHERE (actor.name = "john doe" OR movie.rating > 8.8) AND movie.votes <= 250)
@@ -37,38 +41,42 @@ WHERE (actor.name = "john doe" OR movie.rating > 8.8) AND movie.votes <= 250)
WHERE actor.age >= director.age AND actor.age > 32
```
-It is also possible to specify equality predicates within nodes using the curly braces as such:
+## Inline Property Filters
+
+You can specify equality predicates directly within node patterns using curly braces:
```sql
(:President {name:"Jed Bartlett"})-[:WON]->(:State)
```
-Here we've required that the president node's name will have the value "Jed Bartlett".
+This requires that the president node's `name` property equals "Jed Bartlett".
+
+Inline predicates are functionally equivalent to predicates specified in the WHERE clause.
-There's no difference between inline predicates and predicates specified within the WHERE clause.
+## Pattern Predicates
-It is also possible to filter on graph patterns. The following queries, which return all presidents and the states they won in, produce the same results:
+You can also filter based on graph patterns. These two queries are equivalent and both return presidents and the states they won:
```sh
MATCH (p:President), (s:State) WHERE (p)-[:WON]->(s) RETURN p, s
```
-and
-
```sh
MATCH (p:President)-[:WON]->(s:State) RETURN p, s
```
-Pattern predicates can be also negated and combined with the logical operators AND, OR, and NOT. The following query returns all the presidents that did not win in the states where they were governors:
+Pattern predicates can be negated and combined with logical operators. This query returns presidents who did not win in states where they were governors:
```sh
-MATCH (p:President), (s:State) WHERE NOT (p)-[:WON]->(s) AND (p)->[:governor]->(s) RETURN p, s
+MATCH (p:President), (s:State) WHERE NOT (p)-[:WON]->(s) AND (p)-[:GOVERNOR]->(s) RETURN p, s
```
-Nodes can also be filtered by label:
+## Label Filtering
+
+Nodes can be filtered by label in the WHERE clause:
```sh
MATCH (n)-[:R]->() WHERE n:L1 OR n:L2 RETURN n
```
-When possible, it is preferable to specify the label in the node pattern of the MATCH clause.
+**Best Practice:** When possible, specify labels directly in the node pattern of the MATCH clause for better performance.
diff --git a/cypher/with.md b/cypher/with.md
index 9844046b..13e03337 100644
--- a/cypher/with.md
+++ b/cypher/with.md
@@ -8,20 +8,43 @@ parent: "Cypher Language"
# WITH
-The WITH clause allows parts of queries to be independently executed and have their results handled uniquely.
+The `WITH` clause allows you to chain query parts together, passing results from one part to the next. This enables complex query composition and data manipulations.
-This allows for more flexible query composition as well as data manipulations that would otherwise not be possible in a single query.
+## Use Cases
-If, for example, we wanted to find all children in our graph who are above the average age of all people:
+`WITH` is useful for:
+- Chaining multiple query parts together
+- Performing intermediate aggregations
+- Filtering or transforming results before the next query part
+- Using query modifiers (`DISTINCT`, `ORDER BY`, `LIMIT`, `SKIP`) mid-query
+
+## Example: Filtering by Aggregated Values
+
+Find all children above the average age of all people:
```sh
GRAPH.QUERY DEMO_GRAPH
"MATCH (p:Person) WITH AVG(p.age) AS average_age MATCH (:Person)-[:PARENT_OF]->(child:Person) WHERE child.age > average_age return child
```
-This also allows us to use modifiers like `DISTINCT`, `SKIP`, `LIMIT`, and `ORDER` that otherwise require `RETURN` clauses.
+## Example: Using Modifiers Mid-Query
+
+You can use query modifiers with `WITH` to filter or sort before continuing:
```sh
GRAPH.QUERY DEMO_GRAPH
"MATCH (u:User) WITH u AS nonrecent ORDER BY u.lastVisit LIMIT 3 SET nonrecent.should_contact = true"
-```
\ No newline at end of file
+```
+
+This query:
+1. Matches all users
+2. Orders them by last visit (oldest first)
+3. Limits to the 3 least recent visitors
+4. Sets a flag on those users
+
+## Key Points
+
+- `WITH` acts like a pipeline between query parts
+- Variables not included in `WITH` are not available in subsequent parts
+- You can rename variables using `AS` in the `WITH` clause
+- Aggregations in `WITH` cause implicit grouping (like `RETURN`)
\ No newline at end of file
diff --git a/datatypes.md b/datatypes.md
index 61b882b1..6ca4c883 100644
--- a/datatypes.md
+++ b/datatypes.md
@@ -103,15 +103,13 @@ Since we cannot reason broadly about unknown values, `null` is an important part
Unlike all other scalars, `null` cannot be stored as a property value.
## Temporal Types
-FalkorDB supports the following temporal types that allow modeling and querying time-related data:
-
-## 1. [Date](#Date)
-## 2. [Time](#Time)
-
-## 3. [DateTime](#DateTime)
+FalkorDB supports the following temporal types that allow modeling and querying time-related data:
-## 4. [Duration](#Duration)
+1. [Date](#date) - Calendar dates (YYYY-MM-DD)
+2. [Time](#time) - Time of day (HH:MM:SS)
+3. [DateTime](#datetime) - Combined date and time
+4. [Duration](#duration) - Time intervals
These types follow the ISO 8601 standard and can be used in properties, parameters, and expressions.
@@ -119,16 +117,17 @@ These types follow the ISO 8601 standard and can be used in properties, paramete
Represents a calendar date in the format YYYY-MM-DD.
-Purpose
-Use Date to store and compare dates without time information, e.g. birth dates, due dates, or deadlines.
+**Purpose:**
+Use `Date` to store and compare dates without time information, such as birth dates, due dates, or deadlines.
+
+**Example:**
```cypher
CREATE (:Event { name: "Conference", date: date("2025-09-15") })
```
-#### Interactions
-* Compare using operators (=, <, >, etc.)
-
+**Interactions:**
+* Compare using operators (`=`, `<`, `>`, etc.)
* Extract components using functions:
```cypher
@@ -139,16 +138,18 @@ RETURN date("2025-09-15").day // 15
### Time
-Represents a time of day, in the format hh:mm:ss.
+Represents a time of day in the format HH:MM:SS.
-Purpose
-Use Time to store specific times (e.g. store hours, alarm times) without date context.
+**Purpose:**
+Use `Time` to store specific times (e.g., store hours, alarm times) without date context.
+
+**Example:**
```cypher
CREATE (:Reminder { msg: "Wake up!", at: localtime("07:00:00") })
```
-#### Interactions
+**Interactions:**
* Compare time values:
@@ -168,18 +169,17 @@ RETURN localtime("15:45:20").second // 20
Represents a point in time, combining both date and time. Format: YYYY-MM-DDTHH:MM:SS.
-Purpose
-Use DateTime when both date and time are relevant, e.g. logging events, scheduling, timestamps.
+**Purpose:**
+Use `DateTime` when both date and time are relevant, such as logging events, scheduling, or timestamps.
-Example
+**Example:**
```cypher
CREATE (:Log { message: "System rebooted", at: localdatetime("2025-06-29T13:45:00") })
```
-#### Interactions
-
-* Compare with other DateTime values
+**Interactions:**
+* Compare with other `DateTime` values
* Extract parts:
```cypher
@@ -187,7 +187,7 @@ RETURN localdatetime("2025-06-29T13:45:00").year // 2025
RETURN localdatetime("2025-06-29T13:45:00").hour // 13
```
-* Use localdatetime() with no arguments to get the current system time:
+* Use `localdatetime()` with no arguments to get the current system time:
```cypher
RETURN localdatetime()
@@ -195,17 +195,17 @@ RETURN localdatetime()
### Duration
-Represents a span of time. Format: P[n]Y[n]M[n]DT[n]H[n]M[n]S (ISO 8601 Duration).
+Represents a span of time in ISO 8601 Duration format: `P[n]Y[n]M[n]DT[n]H[n]M[n]S`
-Purpose
-Use Duration to represent intervals, e.g. "3 days", "2 hours", or "1 year and 6 months".
+**Purpose:**
+Use `Duration` to represent time intervals, such as "3 days", "2 hours", or "1 year and 6 months".
-Example
+**Example:**
```cypher
CREATE (:Cooldown { period: duration("P3DT12H") })
```
-#### Interactions
+**Interactions:**
* Add/subtract durations with dates or datetimes:
diff --git a/design/result-structure.md b/design/result-structure.md
index 19092c3d..5d25c83c 100644
--- a/design/result-structure.md
+++ b/design/result-structure.md
@@ -9,7 +9,7 @@ redirect_from:
# Result Set Structure
-This document describes the format FalkorDB uses to print data when accessed through the `redis-cli` utility. The [language-specific clients](/clients) retrieve data in a more succinct format, and provide their own functionality for printing result sets.
+This document describes the format FalkorDB uses to print data when accessed through the `redis-cli` utility. The [language-specific clients](/getting-started/clients) retrieve data in a more succinct format, and provide their own functionality for printing result sets.
## Top-level members
diff --git a/genai-tools/index.md b/genai-tools/index.md
index e5363247..19e0953c 100644
--- a/genai-tools/index.md
+++ b/genai-tools/index.md
@@ -8,6 +8,8 @@ redirect_from:
- /llm_integrations
- /llm-integrations.html
- /llm-integrations
+ - /llm_support.html
+ - /llm_support
---
# GenAI Tools
@@ -18,7 +20,7 @@ FalkorDB provides powerful tools and integrations for building intelligent GenAI
- [GraphRAG-SDK](./graphrag-sdk.md): Build intelligent GraphRAG applications with FalkorDB and LLMs.
- [AG2](./ag2.md): Build multi-agent AI systems with AG2 (formerly AutoGen) and FalkorDB GraphRAG.
-- [LangChain](./langchain.md): Integration with LangChain for AI agents with memory.
+- [LangChain](./langchain.md): Integration with LangChain for AI agents with memory (Python and JavaScript/TypeScript).
- [LangGraph](./langgraph.md): Build stateful, multi-actor agentic applications with LangGraph.
- [LlamaIndex](./llamaindex.md): Simplify development of LLM-powered applications with LlamaIndex.
- [GraphRAG Toolkit](./graphrag-toolkit.md): AWS GraphRAG Toolkit integration for building knowledge graph applications.
diff --git a/genai-tools/langchain.md b/genai-tools/langchain.md
index 14a90816..031826a8 100644
--- a/genai-tools/langchain.md
+++ b/genai-tools/langchain.md
@@ -9,12 +9,20 @@ parent: "GenAI Tools"
FalkorDB is integrated with [LangChain](https://www.langchain.com/), bringing powerful graph database capabilities to AI-driven applications. This integration enables the creation of AI agents with memory, enhancing their ability to retain state and context across interactions.
+The FalkorDB LangChain integration is available for both **Python** and **JavaScript/TypeScript** environments, making it easy to build intelligent applications in your preferred language.
+
## Resources
-- π [FalkorDBQAChain Documentation](https://python.langchain.com/docs/use_cases/more/graph/graph_falkordb_qa)
+- π [FalkorDBQAChain Documentation (Python)](https://python.langchain.com/docs/use_cases/more/graph/graph_falkordb_qa)
+- π¦ [@falkordb/langchain-ts Package (JavaScript/TypeScript)](https://www.npmjs.com/package/@falkordb/langchain-ts)
+- π» [FalkorDB-Langchain-js Repository](https://github.com/FalkorDB/FalkorDB-Langchain-js)
- π [Blog: Build AI Agents with Memory β LangChain + FalkorDB](https://www.falkordb.com/blog/building-ai-agents-with-memory-langchain/)
-## Installation
+---
+
+## Python Integration
+
+### Installation
Install LangChain with FalkorDB support:
@@ -22,9 +30,9 @@ Install LangChain with FalkorDB support:
pip install langchain langchain-community falkordb
```
-## Quick Start
+### Quick Start
-### 1. Connect to FalkorDB
+#### 1. Connect to FalkorDB
```python
from langchain_community.graphs import FalkorDBGraph
@@ -39,7 +47,7 @@ graph = FalkorDBGraph(
)
```
-### 2. Create a Knowledge Graph from Text
+#### 2. Create a Knowledge Graph from Text
```python
from langchain.chains import GraphCypherQAChain
@@ -56,7 +64,7 @@ chain = GraphCypherQAChain.from_llm(
)
```
-### 3. Query the Graph
+#### 3. Query the Graph
```python
# Ask natural language questions
@@ -68,9 +76,9 @@ response = chain.run("What other movies did they act in?")
print(response)
```
-## Advanced Usage
+### Advanced Usage
-### Using Graph Memory for Conversational AI
+#### Using Graph Memory for Conversational AI
```python
from langchain.memory import ConversationGraphMemory
@@ -96,7 +104,7 @@ conversation.predict(input="I work as a software engineer")
conversation.predict(input="What do you know about me?")
```
-### Custom Cypher Generation
+#### Custom Cypher Generation
```python
from langchain.chains.graph_qa.cypher import GraphCypherQAChain
@@ -131,7 +139,7 @@ chain = GraphCypherQAChain.from_llm(
response = chain.run("Find all products in the electronics category")
```
-### Loading Data into the Graph
+#### Loading Data into the Graph
```python
from langchain_community.document_loaders import TextLoader
@@ -156,7 +164,7 @@ vector_store = FalkorDBVector.from_documents(
)
```
-### Graph RAG Pattern
+#### Graph RAG Pattern
```python
from langchain.chains import RetrievalQA
@@ -183,6 +191,162 @@ response = qa_chain.run("What are the key features of our product?")
print(response)
```
+---
+
+## JavaScript/TypeScript Integration
+
+FalkorDB also provides a JavaScript/TypeScript integration for LangChain applications through the [@falkordb/langchain-ts](https://www.npmjs.com/package/@falkordb/langchain-ts) package.
+
+### Installation
+
+```bash
+npm install @falkordb/langchain-ts falkordb langchain @langchain/openai
+```
+
+### Quick Start (JS/TS)
+
+```typescript
+import { FalkorDBGraph } from "@falkordb/langchain-ts";
+import { ChatOpenAI } from "@langchain/openai";
+import { GraphCypherQAChain } from "@langchain/community/chains/graph_qa/cypher";
+
+// Initialize FalkorDB connection
+const graph = await FalkorDBGraph.initialize({
+ host: "localhost",
+ port: 6379,
+ graph: "movies"
+});
+
+// Set up the language model
+const model = new ChatOpenAI({ temperature: 0 });
+
+// Create and populate the graph
+await graph.query(
+ "CREATE (a:Actor {name:'Bruce Willis'})" +
+ "-[:ACTED_IN]->(:Movie {title: 'Pulp Fiction'})"
+);
+
+// Refresh the graph schema
+await graph.refreshSchema();
+
+// Create a graph QA chain
+const chain = GraphCypherQAChain.fromLLM({
+ llm: model,
+ graph: graph as any,
+});
+
+// Ask questions about your graph
+const response = await chain.run("Who played in Pulp Fiction?");
+console.log(response);
+// Output: Bruce Willis played in Pulp Fiction.
+
+await graph.close();
+```
+
+> **Alternative Connection:** You can also connect using a URL format:
+> ```typescript
+> const graph = await FalkorDBGraph.initialize({
+> url: "falkor://localhost:6379",
+> graph: "movies"
+> });
+> ```
+
+### Key Features (JS/TS)
+
+- **Natural Language Querying**: Convert questions to Cypher queries automatically
+- **Schema Management**: Automatic schema refresh and retrieval
+- **Type Safety**: Full TypeScript support with type definitions
+- **Promise-based API**: Modern async/await patterns
+
+### API Reference (JS/TS)
+
+#### `FalkorDBGraph.initialize(config)`
+
+Create and initialize a new FalkorDB connection.
+
+**Config Options:**
+- `host` (string): Database host (default: "localhost")
+- `port` (number): Database port (default: 6379)
+- `graph` (string): Graph name to use
+- `url` (string): Alternative connection URL format: `falkor[s]://[[username][:password]@][host][:port][/db-number]`
+- `enhancedSchema` (boolean): Enable enhanced schema details
+
+**Example with URL:**
+```typescript
+// Connect using URL format
+const graph = await FalkorDBGraph.initialize({
+ url: "falkor://localhost:6379",
+ graph: "myGraph"
+});
+
+// With authentication
+const graph = await FalkorDBGraph.initialize({
+ url: "falkor://username:password@localhost:6379",
+ graph: "myGraph"
+});
+```
+
+#### `query(query: string)`
+
+Execute a Cypher query on the graph.
+
+```typescript
+const result = await graph.query(
+ "MATCH (n:Person) RETURN n.name LIMIT 10"
+);
+```
+
+#### `refreshSchema()`
+
+Update the graph schema information.
+
+```typescript
+await graph.refreshSchema();
+console.log(graph.getSchema());
+```
+
+### Advanced Usage (JS/TS)
+
+#### Custom Cypher Queries
+
+```typescript
+const graph = await FalkorDBGraph.initialize({
+ host: "localhost",
+ port: 6379,
+ graph: "movies"
+});
+
+// Complex query
+const result = await graph.query(`
+ MATCH (a:Actor)-[:ACTED_IN]->(m:Movie)
+ WHERE m.year > 2000
+ RETURN a.name, m.title, m.year
+ ORDER BY m.year DESC
+ LIMIT 10
+`);
+
+console.log(result.data);
+```
+
+#### Working with Schema (JS/TS)
+
+```typescript
+await graph.refreshSchema();
+
+// Get formatted schema
+const schema = graph.getSchema();
+console.log(schema);
+
+// Get structured schema
+const structuredSchema = graph.getStructuredSchema();
+console.log(structuredSchema.nodeProps);
+console.log(structuredSchema.relationships);
+```
+
+For more examples and source code, see the [@falkordb/langchain-ts repository](https://github.com/FalkorDB/FalkorDB-Langchain-js).
+
+---
+
## Use Cases
- **Conversational AI with Memory**: Build chatbots that remember user context across sessions
diff --git a/getting-started/configuration.md b/getting-started/configuration.md
index 3c005d70..f877c785 100644
--- a/getting-started/configuration.md
+++ b/getting-started/configuration.md
@@ -14,7 +14,7 @@ redirect_from:
FalkorDB supports [Redis configuration](https://redis.io/docs/management/config/) and multiple module configuration parameters.
Some of these parameters can only be set at load-time, while other parameters can be set either on load-time or on run-time.
-For example the following will run the server with global authentication password and 4 threads.
+For example, the following command will run the server with global authentication password and 4 threads:
```sh
docker run -p 6379:6379 -p 3000:3000 -it -e REDIS_ARGS="--requirepass falkordb" -e FALKORDB_ARGS="THREAD_COUNT 4" --rm falkordb/falkordb:latest
@@ -25,9 +25,11 @@ docker run -p 6379:6379 -p 3000:3000 -it -e REDIS_ARGS="--requirepass falkordb"
> docker run -p 6379:6379 -it -e REDIS_ARGS="--requirepass falkordb" -e FALKORDB_ARGS="THREAD_COUNT 4" --rm falkordb/falkordb-server:latest
> ```
-## Setting configuration parameters on module load
+## Setting Configuration Parameters on Module Load
-Setting configuration parameters at load-time is done by appending arguments after the `--loadmodule` argument when starting a server from the command line or after the `loadmodule` directive in a Redis config file. For example:
+Configuration parameters can be set at load-time by appending arguments after the `--loadmodule` argument when starting a server from the command line or after the `loadmodule` directive in a Redis config file.
+
+### Examples
In [redis.conf](https://redis.io/docs/manual/config/):
@@ -59,9 +61,9 @@ Or for production use:
docker run -p 6379:6379 -it -e FALKORDB_ARGS="[OPT VAL]" --rm falkordb/falkordb-server:latest
```
-## Setting configuration parameters at run-time (for supported parameters)
+## Setting Configuration Parameters at Run-Time (for Supported Parameters)
-FalkorDB exposes the `GRAPH.CONFIG` command to allowing for the setting and retrieval of configuration parameters at run-time.
+FalkorDB exposes the `GRAPH.CONFIG` command for setting and retrieving configuration parameters at run-time.
To set the value of a configuration parameter at run-time (for supported parameters), simply run:
diff --git a/getting-started/index.md b/getting-started/index.md
index ff255f24..a1a65987 100644
--- a/getting-started/index.md
+++ b/getting-started/index.md
@@ -12,8 +12,7 @@ redirect_from:
# Getting Started with FalkorDB
-This guide will walk you through setting up FalkorDB, modeling a social network as a graph,
-and accessing it using the [FalkorDB Python client](/getting-started/clients) with [Cypher](/cypher).
+This guide will walk you through setting up FalkorDB, modeling a social network as a graph, and accessing it using one of the [FalkorDB client libraries](/getting-started/clients) with the [Cypher](/cypher) query language.
---
@@ -58,15 +57,19 @@ Let's create a simple graph for a social network where:
### Graph Schema
-| Node Type | Properties |
-|-----------|--------------------------|
-| User | `id`, `name`, `email` |
-| Post | `id`, `content`, `date` |
+**Node Types:**
-| Relationship Type | Start Node | End Node | Properties |
-|-------------------|------------|----------|--------------|
-| FRIENDS_WITH | User | User | `since` |
-| CREATED | User | Post | `time` |
+| Node Type | Properties | Description |
+|-----------|--------------------------|---------------------------------------|
+| User | `id`, `name`, `email` | Represents a user in the social network |
+| Post | `id`, `content`, `date` | Represents a post created by a user |
+
+**Relationship Types:**
+
+| Relationship Type | Start Node | End Node | Properties | Description |
+|-------------------|------------|----------|--------------|------------------------------------------|
+| FRIENDS_WITH | User | User | `since` | Indicates friendship between two users |
+| CREATED | User | Post | `time` | Connects a user to their created posts |

diff --git a/index.md b/index.md
index fd5bdd0a..87f4a75c 100644
--- a/index.md
+++ b/index.md
@@ -5,6 +5,9 @@ nav_order: 1
description: "The fastest way to your knowledge"
permalink: /
---
+
+[](https://trendshift.io/repositories/14787)
+
[](https://hub.docker.com/r/falkordb/falkordb/)
[](https://discord.gg/ErBEqN9E)
[](https://app.falkordb.cloud)
@@ -17,33 +20,33 @@ permalink: /
### About FalkorDB
FalkorDB delivers an **accurate, multi-tenant RAG solution powered by a low-latency, scalable graph database technology.**
-* Our solution is purpose-built for development teams working with complex, interconnected dataβwhether structured or unstructuredβin real-time or interactive user environments.
+* Our solution is purpose-built for development teams working with complex, interconnected dataβwhether structured or unstructuredβin real-time or interactive user environments.
-* The system supports the OpenCypher query language with proprietary enhancements that streamline interactions with graph data, and its efficient graph traversal and query capabilities render it well-suited for production environments.
+* The system supports the OpenCypher query language with proprietary enhancements that streamline interactions with graph data. Its efficient graph traversal and query capabilities make it well-suited for production environments.
### Choose Your Path
-* **Graph Path:** If you're interested in utilizing FalkorDB as a property graph database with OpenCypher support, continue with the sections below.
-* **GraphRAG Path:** If you're aiming to implement advanced graph reasoning and generative AI tasks, jump directly to the [GraphRAG SDK](https://github.com/FalkorDB/GraphRAG-SDK) section [1].
+* **Graph Database Path:** If you're interested in using FalkorDB as a property graph database with OpenCypher support, continue with the sections below.
+* **GraphRAG Path:** If you're aiming to implement advanced graph reasoning and generative AI tasks, explore our [GenAI Tools](/genai-tools) section, starting with the [GraphRAG SDK](/genai-tools/graphrag-sdk).
## Primary Features
* Adopts the [Property Graph Model](https://github.com/opencypher/openCypher/blob/master/docs/property-graph-model.adoc)
* Supports [OpenCypher](http://www.opencypher.org/) query language with proprietary extensions
-* Offers [Full-Text Search](/cypher/indexing#full-text-indexing), [Vector Similarity](/cypher/indexing#vector-indexing) & [Numeric indexing](/cypher/indexing).
-* Interacts via either [RESP](https://redis.io/docs/reference/protocol-spec/) and [Bolt](https://en.wikipedia.org/wiki/Bolt_(network_protocol)) protocols
-* Graphs represented as sparse adjacency matrices
-* Supports GraphRAG with the [GraphRAG SDK](https://github.com/FalkorDB/GraphRAG-SDK) for advanced graph reasoning and generative AI tasks.
+* Offers [Full-Text Search](/cypher/indexing/fulltext-index), [Vector Similarity](/cypher/indexing/vector-index), and [Range indexing](/cypher/indexing/range-index) for efficient querying
+* Supports both [RESP](https://redis.io/docs/reference/protocol-spec/) and [Bolt](https://en.wikipedia.org/wiki/Bolt_(network_protocol)) protocols for flexible connectivity
+* Uses sparse adjacency matrix representation for efficient graph storage
+* Provides GraphRAG capabilities through the [GraphRAG SDK](/genai-tools/graphrag-sdk) for advanced graph reasoning and generative AI tasks
## Get Started
-Launch an instance using docker, or use [FalkorDB Clouds](https://app.falkordb.cloud)
+Launch an instance using Docker, or use [FalkorDB Cloud](https://app.falkordb.cloud)
```sh
docker run -p 6379:6379 -p 3000:3000 -it --rm falkordb/falkordb:latest
```
-Once loaded you can interact with FalkorDB using any of the supported [client libraries](/clients)
+Once loaded you can interact with FalkorDB using any of the supported [client libraries](/getting-started/clients)
Here we'll use [FalkorDB Python client](https://pypi.org/project/FalkorDB/) to create a small graph representing a subset of motorcycle riders and teams taking part in the MotoGP league, once created we'll start querying our data.
@@ -238,7 +241,7 @@ For additional demos please see visit [Demos](https://github.com/FalkorDB/demos)
## Client libraries
Language-specific clients have been written by the community and the FalkorDB team.
-The full list and links can be found on the [Clients](/clients) page.
+The full list and links can be found on the [Client Libraries](/getting-started/clients) page.
## Data import
diff --git a/integration/bolt-support.md b/integration/bolt-support.md
index 948b4f5c..998a36b0 100644
--- a/integration/bolt-support.md
+++ b/integration/bolt-support.md
@@ -6,10 +6,14 @@ parent: "Integration"
redirect_from:
- /bolt-support.html
- /bolt-support
+ - /bolt_support.html
+ - /bolt_support
---
# [EXPERIMENTAL] BOLT protocol support for FalkorDB
+> **Note:** For production use cases, please use our [official client libraries](../getting-started/clients.md) instead.
+
FalkorDB provides an experimental support for querying using BOLT drivers.
We intend to extend the support in the future versions, the current version is not meant to be used in production.
This guide will walk you through the process of connecting to FalkorDB using the [BOLT protocol](https://en.wikipedia.org/wiki/Bolt_(network_protocol))
diff --git a/integration/langchain-js.md b/integration/langchain-js.md
deleted file mode 100644
index 80a606ab..00000000
--- a/integration/langchain-js.md
+++ /dev/null
@@ -1,190 +0,0 @@
----
-title: "LangChain JS/TS"
-nav_order: 2
-description: "LangChain JavaScript/TypeScript integration for FalkorDB"
-parent: "Integration"
----
-
-
-
-# LangChain JS/TS Integration with FalkorDB
-
-The [@falkordb/langchain-ts](https://www.npmjs.com/package/@falkordb/langchain-ts) package enables developers to integrate FalkorDB with LangChain applications. The integration allows applications to accept natural language questions, generate Cypher queries automatically, retrieve relevant context from the graph database, and return responses in natural language.
-
-## Installation
-
-### Step 1
-
-```bash
-npm install @falkordb/langchain-ts falkordb
-```
-
-### Step 2
-> Ensure LangChain and a language model are installed
-
-```bash
-npm install langchain @langchain/openai
-```
-
-## Getting Started
-
-### Movie data example
-In this example, we'll initialize the connection to FalkorDB, define a language model (E.g, OpenAI), and both create and populate the graph with movie-related data. **We'll then query the graph in natural language to see the integration at work.**
-> Note: You can change the LLM's temperature
-
-```typescript
-import { FalkorDBGraph } from "@falkordb/langchain-ts";
-import { ChatOpenAI } from "@langchain/openai";
-import { GraphCypherQAChain } from "@langchain/community/chains/graph_qa/cypher";
-
-// Initialize FalkorDB connection
-const graph = await FalkorDBGraph.initialize({
- host: "localhost",
- port: 6379,
- graph: "movies"
-});
-
-// Set up the language model
-const model = new ChatOpenAI({ temperature: 0 });
-
-// Create and populate the graph with some data
-await graph.query(
- "CREATE (a:Actor {name:'Bruce Willis'})" +
- "-[:ACTED_IN]->(:Movie {title: 'Pulp Fiction'})"
-);
-
-// Refresh the graph schema
-await graph.refreshSchema();
-
-// Create a graph QA chain
-const chain = GraphCypherQAChain.fromLLM({
- llm: model,
- graph: graph as any,
-});
-
-// Ask questions about your graph
-const response = await chain.run("Who played in Pulp Fiction?");
-console.log(response);
-// Output: Bruce Willis played in Pulp Fiction.
-
-// Clean up
-await graph.close();
-```
-
-## API Reference
-
-### FalkorDBGraph
-> The following command creates and initializes a new FalkorDB connection.
-
-#### `initialize(config: FalkorDBGraphConfig): Promise`
-
-**Config Options:**
-
-- `host` (string, optional): Database host. Default: `"localhost"`
-- `port` (number, optional): Database port. Default: `6379`
-- `graph` (string, optional): Graph name to use
-- `url` (string, optional): Alternative connection URL format
-- `enhancedSchema` (boolean, optional): Enable enhanced schema details. Default: `false`
-
-**Example:**
-```typescript
-const graph = await FalkorDBGraph.initialize({
- host: "localhost",
- port: 6379,
- graph: "myGraph",
- enhancedSchema: true
-});
-```
-
-#### `query(query: string): Promise`
-
-Executes a Cypher query on the graph.
-
-```typescript
-const result = await graph.query(
- "MATCH (n:Person) RETURN n.name LIMIT 10"
-);
-```
-
-#### `refreshSchema(): Promise`
-
-Updates the graph schema information.
-
-```typescript
-await graph.refreshSchema();
-console.log(graph.getSchema());
-```
-
-#### `getSchema(): string`
-
-Returns the current graph schema as a formatted string.
-
-#### `getStructuredSchema(): StructuredSchema`
-
-Returns the structured schema object containing node properties, relationship properties, and relationships.
-
-#### `close(): Promise`
-
-Closes the database connection.
-
-```typescript
-await graph.close();
-```
-
-## Advanced Usage
-
-### Custom Cypher Queries
-
-```typescript
-const graph = await FalkorDBGraph.initialize({
- host: "localhost",
- port: 6379,
- graph: "movies"
-});
-
-// Complex query
-const result = await graph.query(`
- MATCH (a:Actor)-[:ACTED_IN]->(m:Movie)
- WHERE m.year > 2000
- RETURN a.name, m.title, m.year
- ORDER BY m.year DESC
- LIMIT 10
-`);
-
-console.log(result.data);
-```
-
-### Multiple Queries
-
-```typescript
-await graph.executeQueries([
- "CREATE (p:Person {name: 'Alice'})",
- "CREATE (p:Person {name: 'Bob'})",
- "MATCH (a:Person {name: 'Alice'}), (b:Person {name: 'Bob'}) CREATE (a)-[:KNOWS]->(b)"
-]);
-```
-
-### Working with Schema
-
-```typescript
-await graph.refreshSchema();
-
-// Get formatted schema
-const schema = graph.getSchema();
-console.log(schema);
-
-// Get structured schema
-const structuredSchema = graph.getStructuredSchema();
-console.log(structuredSchema.nodeProps);
-console.log(structuredSchema.relationships);
-```
-
-## Prerequisites
-
-- Node.js >= 18
-- FalkorDB server running
-- LangChain >= 0.1.0
-
-## Additional Examples
-
-For more examples and source code, see the [@falkordb/langchain-ts repository](https://github.com/FalkorDB/FalkorDB-Langchain-js) on GitHub.
diff --git a/integration/rest.md b/integration/rest.md
index eb1fbf9c..48e74685 100644
--- a/integration/rest.md
+++ b/integration/rest.md
@@ -5,301 +5,503 @@ description: "Rest API detailed doc"
parent: "Integration"
---
-# Rest API
+# FalkorDB Browser REST API
+
+REST API for FalkorDB Browser - Graph Database Management Interface
+
+**Version:** 1.4.6
+
+**Base URL:** Your FalkorDB Browser instance URL
+
+**Authentication:** Bearer Token (JWT)
+
+## Getting Started
+
+### Quick Start Guide
+
+To start using the FalkorDB Browser REST API, follow these simple steps:
+
+#### 1. Authentication
+First, you need to authenticate to get a JWT token:
+
+```bash
+curl -X POST "http://your-falkordb-browser-url/api/auth/tokens/credentials" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "username": "default",
+ "password": "",
+ "host": "localhost",
+ "port": "6379",
+ "tls": "false"
+ }'
+```
+
+This will return a JWT token that you'll use for all subsequent requests:
+```json
+{
+ "message": "Token created successfully",
+ "token": ""
+}
+```
+
+#### 2. Check Connection Status
+Verify that FalkorDB is running and accessible:
+
+```bash
+curl -X GET "http://your-falkordb-browser-url/api/status" \
+ -H "Authorization: Bearer $JWT_TOKEN"
+```
+
+#### 3. List Available Graphs
+See what graphs are available in your FalkorDB instance:
+
+```bash
+AUTH_HEADER="Authorization: Bearer ${JWT_TOKEN}"
+curl -X GET "http://your-falkordb-browser-url/api/graph" \
+ -H "$AUTH_HEADER"
+```
+
+#### 4. Execute Your First Query
+Run a simple Cypher query on a graph:
+
+```bash
+AUTH_HEADER="Authorization: Bearer ${JWT_TOKEN}"
+curl -N -X GET "http://your-falkordb-browser-url/api/graph/my_graph?query=MATCH%20(n)%20RETURN%20n%20LIMIT%205&timeout=30000" \
+ -H "$AUTH_HEADER" \
+ -H "Accept: text/event-stream"
+```
## Table of Contents
### Authentication
-- [Login - GET /api/auth/providers](#login---get-apiauthproviders)
-- [Logout - POST /api/auth/signout](#logout---post-apiauthsignout)
-
-### Settings
-- [Set Configuration Value - POST /api/config](#set-configuration-value---post-apiconfig)
-- [Get Configuration Value - GET /api/config](#get-configuration-value---get-apiconfig)
-- [Create New User - POST /api/user](#create-new-user---post-apiuser)
-- [Delete User - DELETE /api/user](#delete-user---delete-apiuser)
-- [Get All Users - GET /api/user](#get-all-users---get-apiuser)
-- [Modify a User - PATCH /api/user/{userName}](#modify-a-user---patch-apiuserusername)
-
-### Graph
-- [Create a Graph & Run A Query - GET /api/graph/{graphName}](#create-a-graph--run-a-query---get-apigraphgraphname)
-- [Delete a Graph - DELETE /api/graph/{graphName}](#delete-a-graph---delete-apigraphgraphname)
-- [Get All Graphs - GET /api/graph](#get-all-graphs---get-apigraph)
-- [Duplicate a Graph - POST /api/graph/{destinationGraphName}](#duplicate-a-graph---post-apigraphdestinationgraphname)
-- [Get Graph Count - GET /api/graph/{graphName}/count](#get-graph-count---get-apigraphgraphnamecount)
-- [Add Node Attribute - POST /api/graph/{graphName}/{id}/{attribute}](#add-node-attribute---post-apigraphgraphnameidattribute)
-- [Delete Node Attribute - DELETE /api/graph/{graphName}/{id}/{attribute}](#delete-node-attribute---delete-apigraphgraphnameidattribute)
-- [Add Node Label - POST /api/graph/{graphName}/{id}/label](#add-node-label---post-apigraphgraphnameidlabel)
-- [Delete Node Label - DELETE /api/graph/{graphName}/{id}/label](#delete-node-label---delete-apigraphgraphnameidlabel)
-- [Delete Node - DELETE /api/graph/{graphName}/{id}](#delete-node---delete-apigraphgraphnameid)
-
-### Schema
-- [Create New Schema & Run A Query - GET /api/graph/{schemaName}](#create-new-schema--run-a-query---get-apigraphschemaname)
-- [Delete a Schema - DELETE /api/graph/{schemaName}](#delete-a-schema---delete-apigraphschemaname)
-- [Get Schema Count - GET /api/schema/{schemaName}/count](#get-schema-count---get-apischemaschemaname-count)
-- [Add Schema Node - POST /api/schema/{schemaName}/{id}](#add-schema-node---post-apischemaschemanameid)
-- [Delete Schema Node - DELETE /api/schema/{schemaName}/{id}](#delete-schema-node---delete-apischemaschemanameid)
-- [Add Schema Attribute - PATCH /api/schema/{schemaName}/{id}/{attribute}](#add-schema-attribute---patch-apischemaschemanameidattribute)
-- [Delete Schema Attribute - DELETE /api/schema/{schemaName}/{id}/{attribute}](#delete-schema-attribute---delete-apischemaschemanameidattribute)
-- [Add Schema Label - POST /api/schema/{schemaName}/{id}/label](#add-schema-label---post-apischemaschemanameidlabel)
-- [Delete Schema Label - DELETE /api/schema/{schemaName}/{id}/label](#delete-schema-label---delete-apischemaschemanameidlabel)
+- [Generate JWT Token with Credentials - POST /api/auth/tokens/credentials](#generate-jwt-token-with-credentials---post-apiauthtokenscredentials)
+- [List JWT tokens - GET /api/auth/tokens](#list-jwt-tokens---get-apiauthtokens)
+- [Get token metadata - GET /api/auth/tokens/{tokenId}](#get-token-metadata---get-apiauthtokenstokenid)
+- [Revoke token by ID - DELETE /api/auth/tokens/{tokenId}](#revoke-token-by-id---delete-apiauthtokenstokenid)
+
+### Status
+- [Check FalkorDB connection status - GET /api/status](#check-falkordb-connection-status---get-apistatus)
+
+### Graph Management
+- [List all graphs - GET /api/graph](#list-all-graphs---get-apigraph)
+- [Execute graph query - GET /api/graph/{graph}](#execute-graph-query---get-apigraphgraph)
+- [Create or verify a graph - POST /api/graph/{graph}](#create-or-verify-a-graph---post-apigraphgraph)
+- [Rename graph - PATCH /api/graph/{graph}](#rename-graph---patch-apigraphgraph)
+- [Delete a graph - DELETE /api/graph/{graph}](#delete-a-graph---delete-apigraphgraph)
+- [Get query execution plan - GET /api/graph/{graph}/explain](#get-query-execution-plan---get-apigraphgraphexplain)
+- [Profile query execution - GET /api/graph/{graph}/profile](#profile-query-execution---get-apigraphgraphprofile)
+- [Get graph information - GET /api/graph/{graph}/info](#get-graph-information---get-apigraphgraphinfo)
+- [Get graph element counts - GET /api/graph/{graph}/count](#get-graph-element-counts---get-apigraphgraphcount)
+- [Export graph data - GET /api/graph/{graph}/export](#export-graph-data---get-apigraphgraphexport)
+- [Duplicate a graph - PATCH /api/graph/{graph}/duplicate](#duplicate-a-graph---patch-apigraphgraphduplicate)
+- [Get node information - GET /api/graph/{graph}/{node}](#get-node-information---get-apigraphgraphnode)
+- [Delete node or relationship - DELETE /api/graph/{graph}/{node}](#delete-node-or-relationship---delete-apigraphgraphnode)
+- [Add node label - POST /api/graph/{graph}/{node}/label](#add-node-label---post-apigraphgraphnodelabel)
+- [Remove node label - DELETE /api/graph/{graph}/{node}/label](#remove-node-label---delete-apigraphgraphnodelabel)
+- [Set node/relationship property - POST /api/graph/{graph}/{node}/{key}](#set-noderelationship-property---post-apigraphgraphnodekey)
+- [Remove node/relationship property - DELETE /api/graph/{graph}/{node}/{key}](#remove-noderelationship-property---delete-apigraphgraphnodekey)
+
+### Configuration Management
+- [Get all configuration values - GET /api/graph/config](#get-all-configuration-values---get-apigraphconfig)
+- [Get specific configuration value - GET /api/graph/config/{config}](#get-specific-configuration-value---get-apigraphconfigconfig)
+- [Set configuration value - POST /api/graph/config/{config}](#set-configuration-value---post-apigraphconfigconfig)
+
+
+
+### User Management
+- [List all users - GET /api/user](#list-all-users---get-apiuser)
+- [Create new user - POST /api/user](#create-new-user---post-apiuser)
+- [Delete multiple users - DELETE /api/user](#delete-multiple-users---delete-apiuser)
+- [Update user role - PATCH /api/user/{user}](#update-user-role---patch-apiuseruser)
---
## Authentication
-### **Login** - `GET /api/auth/providers`
+All endpoints except `/api/auth/tokens/credentials` require authentication using a JWT bearer token in the Authorization header:
+```http
+Authorization: Bearer
+```
-This endpoint retrieves information about authentication providers and their respective URLs for sign-in and callback.
+### **Generate JWT Token with Credentials** - `POST /api/auth/tokens/credentials`
+
+Authenticate with direct credentials and generate a JWT Personal Access Token (PAT) for external API access, CLI tools, or programmatic access. This endpoint does NOT require an existing session.
+
+#### Request Body
+
+- Content-Type: `application/json`
+- Required fields: `username`, `host`, `port`, `tls`
+- Optional fields: `password`, `name`, `expiresAt`, `ttlSeconds`
+
+Example request:
+```json
+{
+ "username": "default",
+ "password": "",
+ "name": "API Token",
+ "expiresAt": null,
+ "ttlSeconds": 31622400,
+ "host": "localhost",
+ "port": "6379",
+ "tls": "false"
+}
+```
+
+**Request Parameters:**
+- `username` (required): Username for database connection
+- `password` (optional): Password for database connection. Can be omitted (or empty) only when using the `default` user on localhost; otherwise a non-empty password is required
+- `name` (optional): Token name
+- `expiresAt` (optional): Token expiration date in ISO 8601 format
+- `ttlSeconds` (optional): Time-to-live in seconds (max: 31622400)
+- `host` (required): FalkorDB host
+- `port` (required): FalkorDB port
+- `tls` (required): Enable TLS connection - "true" or "false"
#### Responses
-- **200**: Successful authentication provider retrieval
+- **200**: Token generated successfully
- Content-Type: `application/json`
- Example response:
```json
{
- "credentials": {
- "id": "credentials",
- "name": "Credentials",
- "type": "credentials",
- "signinUrl": "http://localhost:3000/api/auth/signin/credentials",
- "callbackUrl": "http://localhost:3000/api/auth/callback/credentials"
- }
+ "message": "Token created successfully",
+ "token": ""
}
```
-### **Logout** - `POST /api/auth/signout`
+- **400**: Bad request - Invalid JSON, validation error, expiration date in the past, or invalid TTL value
+ - Content-Type: `application/json`
+ - Example response:
-This endpoint signs out a user, ending their authenticated session.
+ ```json
+ {
+ "message": "Expiration date must be in the future"
+ }
+ ```
-#### Request Body
+- **401**: Authentication failed - Invalid credentials or connection failed
+ - Content-Type: `application/json`
+ - Example response:
-- Content-Type: `application/x-www-form-urlencoded`
-- Example request:
+ ```json
+ {
+ "message": "Invalid credentials or connection failed"
+ }
+ ```
+
+- **500**: Server configuration error - Missing NEXTAUTH_SECRET
+ - Content-Type: `application/json`
+ - Example response:
```json
{
- "csrfToken": "insert csrfToken",
- "callbackUrl": "/login",
- "json": true
+ "message": "Server configuration error: NEXTAUTH_SECRET not set"
}
```
+### **List JWT tokens** - `GET /api/auth/tokens`
+
+Get a list of active JWT tokens. Admins see all tokens, regular users see only their own tokens.
+
+#### Headers
+- `Authorization: Bearer ` (required)
+
#### Responses
-- **200**: Successful logout
+- **200**: List of tokens retrieved successfully
- Content-Type: `application/json`
- Example response:
```json
{
- "url": "http://localhost:3000/api/auth/signout?csrf=true"
+ "tokens": [
+ {
+ "user_id": "7262bcaecc2b06ff66e28ede90e6dce39c218685af9272d7a3fbd63ae08d17c2",
+ "token_id": "1761055513181-215c579b-c6e1-4f10-9b07-aacbf89cda21",
+ "created_at": "2025-10-21T14:05:13.182Z",
+ "expires_at": "2026-10-21T14:05:13.182Z",
+ "last_used": null,
+ "name": "API Token",
+ "permissions": ["Admin"],
+ "username": "adminuser"
+ }
+ ],
+ "count": 8
}
```
----
+- **401**: Authentication failed - invalid or missing token
+- **500**: Internal server error
-## Settings
+### **Get token metadata** - `GET /api/auth/tokens/{tokenId}`
-### **Set Configuration Value** - `POST /api/config`
+Get detailed metadata for a specific JWT token by its token ID. Admins can view any token, regular users can only view their own tokens.
-This endpoint sets a configuration value for `MAX_QUEUED_QUERIES`.
+#### Headers
+- `Authorization: Bearer ` (required)
#### Parameters
-
-- `cookie` (header, required): Cookie header with session and auth tokens.
-- `config` (query, required): The configuration name.
-- `value` (query, required): The integer value to set.
+- `tokenId` (path, required): Token ID to retrieve
+ - Example: `1761053108078-554350d7-c965-4ed7-8d32-679b7f705e81`
#### Responses
-- **200**: Successful configuration update
+- **200**: Token metadata retrieved successfully
- Content-Type: `application/json`
- Example response:
```json
{
- "config": "OK"
+ "token": {
+ "user_id": "e5d09e7d2141f77f80008ff73f04104b9484f59baa8e19a4ea758495d289fd0f",
+ "token_id": "1761053108078-554350d7-c965-4ed7-8d32-679b7f705e81",
+ "created_at": "2025-10-21T13:25:08.085Z",
+ "expires_at": "2026-10-21T13:25:08.085Z",
+ "last_used": null,
+ "name": "API Token",
+ "permissions": ["Read-Only"],
+ "username": "readonlyuser"
+ }
}
```
-### **Get Configuration Value** - `GET /api/config`
-
-This endpoint retrieves the value for `MAX_QUEUED_QUERIES`.
-
-#### Parameters
-
-- `cookie` (header, required): Cookie header with session and auth tokens.
-- `config` (query, required): The name of the configuration to retrieve.
+- **401**: Authentication failed - invalid or missing token
+- **403**: Forbidden - You can only view your own tokens (unless you are an Admin)
+ - Content-Type: `application/json`
+ - Example response:
-#### Responses
+ ```json
+ {
+ "message": "Forbidden: You can only view your own tokens"
+ }
+ ```
-- **200**: Successful configuration retrieval
+- **404**: Token not found
- Content-Type: `application/json`
- Example response:
```json
{
- "config": [
- "MAX_QUEUED_QUERIES",
- 25
- ]
+ "message": "Token not found"
}
```
-### **Create New User** - `POST /api/user`
+- **500**: Internal server error
-This endpoint creates a new user with specified credentials.
+### **Revoke token by ID** - `DELETE /api/auth/tokens/{tokenId}`
-#### Request Body
+Revoke a specific JWT token by its token ID. Once revoked, the token cannot be used for authentication. Admins can revoke any token, regular users can only revoke their own tokens.
-- Content-Type: `application/json`
-- Example request:
+#### Headers
+- `Authorization: Bearer ` (required)
+
+#### Parameters
+- `tokenId` (path, required): Token ID to revoke
+ - Example: `1761053108078-554350d7-c965-4ed7-8d32-679b7f705e81`
+
+#### Responses
+
+- **200**: Token revoked successfully
+ - Content-Type: `application/json`
+ - Example response:
```json
{
- "username": "user",
- "password": "Pass123@",
- "role": "Read-Write"
+ "message": "Token revoked successfully",
+ "tokenId": "1761053108078-554350d7-c965-4ed7-8d32-679b7f705e81"
}
```
-#### Responses
-
-- **201**: User created successfully
+- **400**: Bad request - Token is already revoked
- Content-Type: `application/json`
- Example response:
```json
{
- "message": "User created"
+ "message": "Token is already revoked"
}
```
-### **Delete User** - `DELETE /api/user`
+- **401**: Authentication failed - invalid or missing token
-This endpoint deletes a user based on their username and role.
+- **403**: Forbidden - You can only revoke your own tokens (unless you are an Admin)
+ - Content-Type: `application/json`
+ - Example response:
-#### Request Body
+ ```json
+ {
+ "message": "Forbidden: You can only revoke your own tokens"
+ }
+ ```
-- Content-Type: `application/json`
-- Example request:
+- **404**: Token not found
+ - Content-Type: `application/json`
+ - Example response:
```json
{
- "users": [
- {
- "username": "userName",
- "role": "Read-Write"
- }
- ]
+ "message": "Token not found"
}
```
+- **500**: Internal server error
+
+---
+
+## Status
+
+### **Check FalkorDB connection status** - `GET /api/status`
+
+Returns the current connection status to the FalkorDB database.
+
+#### Headers
+- `Authorization: Bearer ` (required)
+
#### Responses
-- **200**: User deleted successfully
+- **200**: Database is online and accessible
- Content-Type: `application/json`
- Example response:
```json
{
- "message": "User deleted"
+ "status": "online"
}
```
-### **Get All Users** - `GET /api/user`
+- **404**: Database is offline or not accessible
+- **500**: Internal server error
+
+---
+
+## Graph Management
-This endpoint retrieves a list of all users.
+### **List all graphs** - `GET /api/graph`
+
+Get a list of all graphs in the FalkorDB instance.
+
+#### Headers
+- `Authorization: Bearer ` (required)
#### Responses
-- **200**: List of users retrieved successfully
+- **200**: List of graphs retrieved successfully
- Content-Type: `application/json`
- Example response:
```json
{
- "result": [
- {
- "username": "default",
- "role": "Admin",
- "checked": false
- }
+ "opts": [
+ "social_network",
+ "product_catalog",
+ "user_interactions"
]
}
```
-### **Modify A User** - `PATCH /api/user/{userName}`
+- **400**: Bad request
+- **500**: Internal server error
-This endpoint updates the role of a specific user.
+### **Execute graph query** - `GET /api/graph/{graph}`
+
+Execute a Cypher query on the specified graph (Server-Sent Events).
+
+#### Headers
+- `Authorization: Bearer ` (required)
#### Parameters
+- `graph` (path, required): Graph name to query
+ - Example: `social_network`
+- `query` (query, required): Cypher query to execute
+ - Example: `MATCH (n) RETURN n LIMIT 10`
+- `timeout` (query, required): Query timeout in milliseconds
+ - Example: `30000`
+
+#### Responses
-- `cookie` (header, required): Cookie header with session and auth tokens.
-- `userName` (path, required): The username of the user to modify.
-- `role` (query, required): The new role to assign to the user (`Admin`, `Read-Only`, `Read-Write`).
+- **200**: Query executed successfully (Server-Sent Events stream)
+
+### **Create or verify a graph** - `POST /api/graph/{graph}`
+
+Create a new graph or verify that a graph exists.
+
+#### Headers
+- `Authorization: Bearer ` (required)
+
+#### Parameters
+- `graph` (path, required): Graph name to create or verify
#### Responses
-- **200**: User updated successfully
+- **200**: Graph created or verified successfully
- Content-Type: `application/json`
- Example response:
```json
{
- "message": "User role updated"
+ "message": "Graph created successfully"
}
```
----
+- **400**: Bad request
+- **500**: Internal server error
-## Graph
+### **Rename graph** - `PATCH /api/graph/{graph}`
-### **Create A Graph & Run A Query** - `GET /api/graph/{graphName}`
+Rename an existing graph to a new name.
-This endpoint creates a graph and runs a query.
+#### Headers
+- `Authorization: Bearer ` (required)
#### Parameters
-
-- `cookie` (header, required): Cookie header with session and auth tokens.
-- `graphName` (path, required): The name of the graph to be created.
-- `query` (query, required): The query to run, such as `RETURN 1`.
+- `graph` (path, required): New graph name
+- `sourceName` (query, required): Current graph name to rename
#### Responses
-- **200**: Graph created and query executed
+- **200**: Graph renamed successfully
- Content-Type: `application/json`
- Example response:
```json
{
- "result": {
- "metadata": [
- "Nodes created: 40",
- "Relationships created: 20",
- "Cached execution: 1",
- "Query internal execution time: 0.201420 milliseconds"
- ],
- "data": [
- {
- "queryData": "exampleData"
- }
- ]
+ "data": {
+ "result": "Graph renamed successfully"
}
}
```
-### **Delete A Graph** - `DELETE /api/graph/{graphName}`
+- **400**: Bad request - graph already exists or missing sourceName
+- **500**: Internal server error
-This endpoint deletes a specified graph.
+### **Delete a graph** - `DELETE /api/graph/{graph}`
-#### Parameters
+Delete a graph from the FalkorDB instance.
+
+#### Headers
+- `Authorization: Bearer ` (required)
-- `cookie` (header, required): Cookie header with session and auth tokens.
-- `graphName` (path, required): The name of the graph to be deleted.
+#### Parameters
+- `graph` (path, required): Graph name to delete
#### Responses
@@ -309,36 +511,113 @@ This endpoint deletes a specified graph.
```json
{
- "message": "GraphName graph deleted"
+ "message": "graph_name graph deleted"
}
```
-### **Get All Graphs** - `GET /api/graph`
+- **400**: Bad request
+- **500**: Internal server error
+
+### **Get query execution plan** - `GET /api/graph/{graph}/explain`
-This endpoint retrieves a list of all graphs.
+Get the execution plan for a Cypher query without executing it.
+
+#### Headers
+- `Authorization: Bearer ` (required)
+
+#### Parameters
+- `graph` (path, required): Graph name
+- `query` (query, required): Cypher query to explain
#### Responses
-- **200**: List of graphs retrieved successfully
+- **200**: Query execution plan returned successfully
+
+### **Profile query execution** - `GET /api/graph/{graph}/profile`
+
+Get detailed profiling information for a Cypher query.
+
+#### Headers
+- `Authorization: Bearer ` (required)
+
+#### Parameters
+- `graph` (path, required): Graph name
+- `query` (query, required): Cypher query to profile
+
+#### Responses
+
+- **200**: Query profiling information returned successfully
+
+### **Get graph information** - `GET /api/graph/{graph}/info`
+
+Get specific information about a graph (functions, property keys, labels, or relationship types).
+
+#### Headers
+- `Authorization: Bearer ` (required)
+
+#### Parameters
+- `graph` (path, required): Graph name
+- `type` (query, required): Type of information to retrieve
+ - Options: `(function)`, `(property key)`, `(label)`, `(relationship type)`
+ - Example: `(label)`
+
+#### Responses
+
+- **200**: Graph information retrieved successfully
- Content-Type: `application/json`
- Example response:
```json
{
- "result": [
- "graphName"
- ]
+ "result": {
+ "data": [
+ {"(label)": "Person"},
+ {"(label)": "Company"}
+ ]
+ }
}
```
-### **Duplicate A Graph** - `POST /api/graph/{destinationGraphName}`
+- **400**: Bad request - missing or invalid type parameter
+
+### **Get graph element counts** - `GET /api/graph/{graph}/count`
+
+Get the count of nodes and relationships in a graph.
+
+#### Headers
+- `Authorization: Bearer ` (required)
+
+#### Parameters
+- `graph` (path, required): Graph name
+
+#### Responses
+
+- **200**: Element counts retrieved successfully
-This endpoint duplicates a graph from source to destination.
+### **Export graph data** - `GET /api/graph/{graph}/export`
+
+Export graph data in various formats.
+
+#### Headers
+- `Authorization: Bearer ` (required)
#### Parameters
+- `graph` (path, required): Graph name
+
+#### Responses
+
+- **200**: Graph data exported successfully
+
+### **Duplicate a graph** - `PATCH /api/graph/{graph}/duplicate`
+
+Create a copy of an existing graph with a new name.
+
+#### Headers
+- `Authorization: Bearer ` (required)
-- `destinationGraphName` (path, required): The name of the destination graph.
-- `sourceName` (query, required): The name of the source graph to duplicate.
+#### Parameters
+- `graph` (path, required): New graph name for the duplicate
+- `sourceName` (query, required): Source graph name to duplicate from
#### Responses
@@ -348,22 +627,29 @@ This endpoint duplicates a graph from source to destination.
```json
{
- "success": "OK"
+ "result": {
+ "status": "Graph duplicated successfully"
+ }
}
```
-### **Get Graph Count** - `GET /api/graph/{graphName}/count`
+- **400**: Bad request - missing sourceName parameter
+- **500**: Internal server error
-This endpoint retrieves the count of nodes and edges in a specified graph.
+### **Get node information** - `GET /api/graph/{graph}/{node}`
-#### Parameters
+Get detailed information about a specific node.
-- `cookie` (header, required): Cookie header with session and auth tokens.
-- `graphName` (path, required): The name of the graph to count nodes and edges.
+#### Headers
+- `Authorization: Bearer ` (required)
+
+#### Parameters
+- `graph` (path, required): Graph name
+- `node` (path, required): Node ID
#### Responses
-- **200**: Graph count retrieved successfully
+- **200**: Node information retrieved successfully
- Content-Type: `application/json`
- Example response:
@@ -372,506 +658,916 @@ This endpoint retrieves the count of nodes and edges in a specified graph.
"result": {
"data": [
{
- "nodes": 7417,
- "edges": 4341
+ "node": {
+ "id": 1,
+ "labels": ["Person"],
+ "properties": {
+ "name": "John Doe",
+ "age": 30
+ }
+ },
+ "relationships": []
}
]
}
}
```
-### **Add Node Attribute** - `POST /api/graph/{graphName}/{id}/{attribute}`
+- **400**: Bad request
+- **500**: Internal server error
-This endpoint adds an attribute to a node in a graph.
+### **Delete node or relationship** - `DELETE /api/graph/{graph}/{node}`
-#### Parameters
+Delete a node or relationship from the graph.
+
+#### Headers
+- `Authorization: Bearer ` (required)
-- `cookie` (header, required): Cookie header with session and auth tokens.
-- `graphName` (path, required): The name of the graph.
-- `id` (path, required): The ID of the node to which the attribute will be added.
-- `attribute` (path, required): The name of the attribute to add.
+#### Parameters
+- `graph` (path, required): Graph name
+- `node` (path, required): Node or relationship ID
#### Request Body
- Content-Type: `application/json`
-- Example request:
+- Required field: `type`
- ```json
- {
- "value": "your_attribute_value",
- "type": true
- }
- ```
+Example request:
+```json
+{
+ "type": true
+}
+```
+
+- `type`: `true` to delete a node, `false` to delete a relationship
#### Responses
-- **200**: Node attribute added successfully
+- **200**: Node or relationship deleted successfully
- Content-Type: `application/json`
- Example response:
```json
{
- "result": {
- "metadata": [
- "Cached execution: 0",
- "Query internal execution time: 0.412958 milliseconds"
- ]
- }
+ "message": "Node deleted successfully"
}
```
-### **Delete Node Attribute** - `DELETE /api/graph/{graphName}/{id}/{attribute}`
+- **400**: Bad request - missing type parameter
+- **500**: Internal server error
-This endpoint deletes an attribute from a node in a graph.
+### **Add node label** - `POST /api/graph/{graph}/{node}/label`
-#### Parameters
+Add a label to a specific node.
+
+#### Headers
+- `Authorization: Bearer ` (required)
-- `cookie` (header, required): Cookie header with session and auth tokens.
-- `graphName` (path, required): The name of the graph.
-- `id` (path, required): The ID of the node from which the attribute will be deleted.
-- `attribute` (path, required): The name of the attribute to delete.
+#### Parameters
+- `graph` (path, required): Graph name
+- `node` (path, required): Node ID
#### Request Body
- Content-Type: `application/json`
-- Example request:
- ```json
- {
- "type": true
- }
- ```
+Example request:
+```json
+{
+ "label": "your_label"
+}
+```
#### Responses
-- **200**: Node attribute deleted successfully
- - Content-Type: `application/json`
- - Example response:
+- **200**: Label added successfully
- ```json
- {
- "result": {
- "metadata": [
- "Cached execution: 0",
- "Query internal execution time: 0.407125 milliseconds"
- ]
- }
- }
- ```
+### **Remove node label** - `DELETE /api/graph/{graph}/{node}/label`
-### **Add Node Label** - `POST /api/graph/{graphName}/{id}/label`
+Remove a label from a specific node.
-This endpoint adds a label to a node in a graph.
+#### Headers
+- `Authorization: Bearer ` (required)
#### Parameters
-
-- `cookie` (header, required): Cookie header with session and auth tokens.
-- `graphName` (path, required): The name of the graph.
-- `id` (path, required): The ID of the node to which the label will be added.
+- `graph` (path, required): Graph name
+- `node` (path, required): Node ID
#### Request Body
- Content-Type: `application/json`
-- Example request:
- ```json
- {
- "label": "your_label_name"
- }
- ```
+Example request:
+```json
+{
+ "label": "your_label"
+}
+```
#### Responses
-- **200**: Node label added successfully
- - Content-Type: `application/json`
- - Example response:
+- **200**: Label removed successfully
- ```json
- {
- "message": "Label added successfully"
- }
- ```
+### **Set node/relationship property** - `POST /api/graph/{graph}/{node}/{key}`
-### **Delete Node Label** - `DELETE /api/graph/{graphName}/{id}/label`
+Set a property value on a node or relationship.
-This endpoint deletes a label from a node in a graph.
+**IMPORTANT:** Use `type=true` for nodes, `type=false` for relationships.
+
+#### Headers
+- `Authorization: Bearer ` (required)
#### Parameters
+- `graph` (path, required): Graph name
+- `node` (path, required): Node or relationship ID
+- `key` (path, required): Property key name
+
+#### Request Body
+
+- Content-Type: `application/json`
+- Required fields: `value`, `type`
+
+Example request:
+```json
+{
+ "value": "your_property_value",
+ "type": true
+}
+```
+
+- `value`: Property value to set
+- `type`: `true` for nodes, `false` for relationships
-- `cookie` (header, required): Cookie header with session and auth tokens.
-- `graphName` (path, required): The name of the graph.
-- `id` (path, required): The ID of the node from which the label will be deleted.
+#### Responses
+
+- **200**: Property set successfully
+
+### **Remove node/relationship property** - `DELETE /api/graph/{graph}/{node}/{key}`
+
+Remove a property from a node or relationship.
+
+**IMPORTANT:** Use `type=true` for nodes, `type=false` for relationships.
+
+#### Headers
+- `Authorization: Bearer ` (required)
+
+#### Parameters
+- `graph` (path, required): Graph name
+- `node` (path, required): Node or relationship ID
+- `key` (path, required): Property key name
#### Request Body
- Content-Type: `application/json`
-- Example request:
+- Required field: `type`
- ```json
- {
- "label": "your_label_name"
- }
- ```
+Example request:
+```json
+{
+ "type": true
+}
+```
+
+- `type`: `true` for nodes, `false` for relationships
#### Responses
-- **200**: Node label deleted successfully
+- **200**: Property removed successfully
+
+---
+
+## Configuration Management
+
+### **Get all configuration values** - `GET /api/graph/config`
+
+Get all FalkorDB configuration parameters and their values.
+
+#### Headers
+- `Authorization: Bearer ` (required)
+
+#### Responses
+
+- **200**: Configuration values retrieved successfully
- Content-Type: `application/json`
- Example response:
```json
{
- "message": "Label removed successfully"
+ "configs": {
+ "MAX_INFO_QUERIES": 700,
+ "CMD_INFO": "server",
+ "TIMEOUT": 1000
+ }
}
```
-### **Delete Node** - `DELETE /api/graph/{graphName}/{id}`
+- **400**: Bad request
+- **500**: Internal server error
-This endpoint deletes a node from a graph.
+### **Get specific configuration value** - `GET /api/graph/config/{config}`
-#### Parameters
+Get the value of a specific configuration parameter.
-- `cookie` (header, required): Cookie header with session and auth tokens.
-- `graphName` (path, required): The name of the graph.
-- `id` (path, required): The ID of the node to delete.
+#### Headers
+- `Authorization: Bearer ` (required)
-#### Request Body
+#### Parameters
+- `config` (path, required): Configuration parameter name
+ - Example: `MAX_INFO_QUERIES`
-- Content-Type: `application/json`
-- Example request:
+#### Responses
+
+- **200**: Configuration value retrieved successfully
+ - Content-Type: `application/json`
+ - Example response:
```json
{
- "type": true
+ "config": 700
}
```
+- **400**: Bad request
+- **500**: Internal server error
+
+### **Set configuration value** - `POST /api/graph/config/{config}`
+
+Set the value of a specific configuration parameter.
+
+#### Headers
+- `Authorization: Bearer ` (required)
+
+#### Parameters
+- `config` (path, required): Configuration parameter name
+ - Example: `MAX_INFO_QUERIES`
+- `value` (query, required): Configuration value to set (numeric values will be parsed as integers except for CMD_INFO)
+ - Example: `700`
+
#### Responses
-- **200**: Node deleted successfully
+- **200**: Configuration value set successfully
- Content-Type: `application/json`
- Example response:
```json
{
- "message": "Node deleted successfully"
+ "config": "OK"
}
```
+- **400**: Bad request - missing value or invalid value
+- **500**: Internal server error
+
---
-## Schema
+
+
+---
+
+## User Management
+
+### **List all users** - `GET /api/user`
+
+Get a list of all FalkorDB users.
+
+#### Headers
+- `Authorization: Bearer ` (required)
#### Responses
-- **200**: Schema node attribute deleted successfully
+- **200**: List of users retrieved successfully
- Content-Type: `application/json`
- Example response:
```json
{
- "message": "Attribute deleted successfully"
+ "result": [
+ {
+ "username": "john_doe",
+ "role": "Read-Write",
+ "selected": false
+ },
+ {
+ "username": "admin_user",
+ "role": "Admin",
+ "selected": false
+ }
+ ]
}
```
-### **Add Schema Label** - `POST /api/schema/{schemaName}/{id}/label`
+- **400**: Bad request
+- **500**: Internal server error
-This endpoint adds a label to a node in a schema.
+### **Create new user** - `POST /api/user`
-#### Parameters
+Create a new FalkorDB user with specified username, password, and role.
-- `cookie` (header, required): Cookie header with session and auth tokens.
-- `schemaName` (path, required): The name of the schema.
-- `id` (path, required): The ID of the node to which the label will be added.
+#### Headers
+- `Authorization: Bearer ` (required)
#### Request Body
- Content-Type: `application/json`
-- Example request:
+- Required fields: `username`, `password`, `role`
- ```json
- {
- "label": "your_label_name"
- }
- ```
+Example request:
+```json
+{
+ "username": "new_user",
+ "password": "secure_password",
+ "role": "Read-Write"
+}
+```
+
+- `username`: Username for the new user
+- `password`: Password for the new user
+- `role`: Role to assign to the user (`Admin`, `Read-Write`, `Read-Only`)
#### Responses
-- **200**: Schema node label added successfully
+- **201**: User created successfully
- Content-Type: `application/json`
- Example response:
```json
{
- "result": {
- "metadata": [
- "Cached execution: 0",
- "Query internal execution time: 0.417250 milliseconds"
- ]
- }
+ "message": "Success"
}
```
-### **Delete Schema Label** - `DELETE /api/schema/{schemaName}/{id}/label`
+ - Headers:
+ - `location`: Location of the created user resource (example: `/api/db/user/new_user`)
-This endpoint deletes a label from a node in a schema.
+- **400**: Bad request - missing parameters
+- **409**: User already exists
+- **500**: Internal server error
-#### Parameters
+### **Delete multiple users** - `DELETE /api/user`
-- `cookie` (header, required): Cookie header with session and auth tokens.
-- `schemaName` (path, required): The name of the schema.
-- `id` (path, required): The ID of the node from which the label will be deleted.
+Delete multiple FalkorDB users by providing an array of usernames.
+
+#### Headers
+- `Authorization: Bearer ` (required)
#### Request Body
- Content-Type: `application/json`
-- Example request:
+- Required field: `users`
- ```json
- {
- "label": "your_label_name"
- }
- ```
+Example request:
+```json
+{
+ "users": [
+ { "username": "user_1741261105156" },
+ { "username": "another_user" }
+ ]
+}
+```
+
+- `users`: Array of user objects to delete
#### Responses
-- **200**: Schema node label deleted successfully
+- **200**: Users deleted successfully
- Content-Type: `application/json`
- Example response:
```json
{
- "result": {
- "metadata": [
- "Cached execution: 0",
- "Query internal execution time: 0.829917 milliseconds"
- ]
- }
+ "message": "Users deleted"
}
```
+
+- **400**: Bad request
+- **500**: Internal server error
+
+### **Update user role** - `PATCH /api/user/{user}`
+
+Update the role of a FalkorDB user.
+
+#### Headers
+- `Authorization: Bearer ` (required)
+
+#### Parameters
+- `user` (path, required): Username to update
+- `role` (query, required): New role for the user (`Admin`, `Read-Write`, `Read-Only`)
+
+#### Responses
+
+- **200**: User role updated successfully
+
+---
+
+## Error Responses
+
+All endpoints may return the following common error responses:
+
+- **401**: Unauthorized - Invalid or missing authentication token
+- **403**: Forbidden - Insufficient permissions for the requested operation
+- **404**: Not Found - Requested resource does not exist
+- **500**: Internal Server Error - Unexpected server error
+
+## Data Types
+
+### Attribute Types
+The following data types are supported for node and relationship attributes:
+
+- `STRING`: Text values
+- `INTEGER`: Numeric integer values
+- `FLOAT`: Numeric decimal values
+- `BOOLEAN`: True/false values
+
+### Attribute Configuration
+When defining attributes, use the following format:
+```json
+[type, default_value, unique, required]
+```
+
+- `type`: One of the supported data types (`STRING`, `INTEGER`, `FLOAT`, `BOOLEAN`)
+- `default_value`: Default value for the attribute
+- `unique`: `"true"` if the attribute must be unique, `"false"` otherwise
+- `required`: `"true"` if the attribute is required, `"false"` otherwise
+
+Example:
+```json
+["STRING", "default_name", "false", "true"]
+```
diff --git a/migration/redisgraph-to-falkordb.md b/migration/redisgraph-to-falkordb.md
index 89afee98..92279041 100644
--- a/migration/redisgraph-to-falkordb.md
+++ b/migration/redisgraph-to-falkordb.md
@@ -7,12 +7,34 @@ redirect_from:
- /redisgraph-to-falkordb
---
-# FalkorDB is compatible with RedisGraph RDB files.
+# RedisGraph to FalkorDB Migration
-For the migration, execute the following steps:
+FalkorDB is fully compatible with RedisGraph RDB (Redis Database) files, making migration straightforward.
-1. Get the latest RDB file from your RedisGraph instance. Ensure you call SAVE or BGSAVE to capture the latest data snapshot.
-2. Load the RDB file into FalkorDB. When using the FalkorDB Docker image, use the following command:
+## Migration Steps
+
+### Step 1: Create RDB Snapshot from RedisGraph
+
+Create a snapshot of your RedisGraph database using the `SAVE` or `BGSAVE` command:
+
+```bash
+# Connect to your RedisGraph instance
+redis-cli
+
+# Create snapshot (blocks server during save)
+SAVE
+
+# Or create snapshot in background (recommended for production)
+BGSAVE
+```
+
+This creates a `dump.rdb` file in your Redis data directory.
+
+### Step 2: Load RDB File into FalkorDB
+
+#### Using Docker
+
+When using the FalkorDB Docker image, mount your RDB file and configure Redis to load it:
```bash
docker run -it -p 6379:6379 -v $(pwd):/data -e REDIS_ARGS="--dir /data --dbfilename dump.rdb" falkordb/falkordb
@@ -21,8 +43,31 @@ For the migration, execute the following steps:
Make sure to place the RDB file in the directory mapped to the Docker volume.
For FalkorDB Cloud, follow the cloud providerβs instructions for uploading and restoring from an RDB file.
-## Additional Tips:
+**Important:** Ensure your `dump.rdb` file is placed in the directory mapped to the Docker volume (`$(pwd)` in the example above).
+
+#### Using FalkorDB Cloud
+
+For FalkorDB Cloud deployments, follow the cloud provider's instructions for uploading and restoring from an RDB file.
+
+## Verification
+
+After loading the RDB file, verify your data:
+
+```bash
+# Connect to FalkorDB
+redis-cli
+
+# List all graphs
+GRAPH.LIST
+
+# Query a graph to verify data
+GRAPH.QUERY your_graph_name "MATCH (n) RETURN count(n)"
+```
+
+## Best Practices
-* Verify the integrity of the RDB file before and after transfer.
-* Consider downtime and data consistency during the migration process.
-* Test the migration process in a staging environment before applying it to production.
+* **Verify RDB Integrity:** Check the RDB file integrity before and after transfer
+* **Plan for Downtime:** Consider downtime requirements and data consistency during migration
+* **Test First:** Always test the migration in a staging environment before production
+* **Backup:** Keep backups of both the source RedisGraph data and the RDB file
+* **Monitor:** After migration, monitor FalkorDB performance and verify queries work correctly
diff --git a/operations/docker.md b/operations/docker.md
new file mode 100644
index 00000000..c1c8cdf9
--- /dev/null
+++ b/operations/docker.md
@@ -0,0 +1,488 @@
+---
+title: "Docker and Docker Compose"
+nav_order: 11
+parent: Operations
+description: "Running FalkorDB with Docker and Docker Compose"
+---
+
+# Running FalkorDB with Docker and Docker Compose
+
+This guide covers how to run FalkorDB using Docker and Docker Compose, providing flexible deployment options for both development and production environments.
+
+## Docker Images
+
+FalkorDB provides two main Docker images:
+
+### 1. `falkordb/falkordb`
+- **Includes**: FalkorDB server + FalkorDB Browser
+- **Use case**: Development, quick start, interactive exploration
+- **Ports**:
+ - `6379` - Redis/FalkorDB server
+ - `3000` - FalkorDB Browser UI
+
+### 2. `falkordb/falkordb-server`
+- **Includes**: FalkorDB server only
+- **Use case**: Production deployments, lighter footprint
+- **Ports**:
+ - `6379` - Redis/FalkorDB server
+
+### 3. `falkordb/falkordb-browser`
+- **Includes**: FalkorDB Browser UI only
+- **Use case**: Running browser separately from the server, custom deployments
+- **Ports**:
+ - `3000` - FalkorDB Browser UI
+- **Configuration**: Requires `FALKORDB_URL` environment variable to connect to a FalkorDB server
+
+## Quick Start with Docker
+
+### Running with Browser (Development)
+
+```bash
+docker run -p 6379:6379 -p 3000:3000 -it --rm falkordb/falkordb:latest
+```
+
+Access the browser at [http://localhost:3000](http://localhost:3000)
+
+### Running Server Only (Production)
+
+```bash
+docker run -p 6379:6379 -it --rm falkordb/falkordb-server:latest
+```
+
+### Running with Authentication
+
+```bash
+docker run -p 6379:6379 -p 3000:3000 -it \
+ -e REDIS_ARGS="--requirepass yourpassword" \
+ --rm falkordb/falkordb:latest
+```
+
+### Running with Custom Configuration
+
+```bash
+docker run -p 6379:6379 -p 3000:3000 -it \
+ -e REDIS_ARGS="--requirepass yourpassword" \
+ -e FALKORDB_ARGS="THREAD_COUNT 4 TIMEOUT 5000" \
+ --rm falkordb/falkordb:latest
+```
+
+## Using Docker Compose
+
+Docker Compose provides a more flexible and maintainable way to run FalkorDB, especially when you need to configure multiple services or manage complex setups.
+
+> **Quick Start**: You can download a ready-to-use docker-compose.yml file from the [FalkorDB repository](https://github.com/FalkorDB/FalkorDB/blob/master/build/docker/docker-compose.yml).
+
+### Basic Docker Compose Setup
+
+Create a `docker-compose.yml` file:
+
+```yaml
+version: '3.8'
+
+services:
+ falkordb:
+ image: falkordb/falkordb:latest
+ container_name: falkordb
+ ports:
+ - "6379:6379"
+ - "3000:3000"
+ environment:
+ - REDIS_ARGS=--requirepass falkordb
+ - FALKORDB_ARGS=THREAD_COUNT 4
+ restart: unless-stopped
+```
+
+Start FalkorDB:
+
+```bash
+docker-compose up -d
+```
+
+Stop FalkorDB:
+
+```bash
+docker-compose down
+```
+
+### Production Setup with Persistence
+
+For production environments, use the server-only image with data persistence:
+
+```yaml
+version: '3.8'
+
+services:
+ falkordb:
+ image: falkordb/falkordb-server:latest
+ container_name: falkordb-server
+ ports:
+ - "6379:6379"
+ environment:
+ - REDIS_ARGS=--requirepass ${FALKORDB_PASSWORD:-falkordb} --appendonly yes
+ - FALKORDB_ARGS=THREAD_COUNT 8 TIMEOUT_MAX 30000
+ volumes:
+ - falkordb_data:/data
+ restart: unless-stopped
+ healthcheck:
+ test: ["CMD", "redis-cli", "ping"]
+ interval: 30s
+ timeout: 10s
+ retries: 3
+
+volumes:
+ falkordb_data:
+ driver: local
+```
+
+Start with custom password:
+
+```bash
+FALKORDB_PASSWORD=your-secure-password docker-compose up -d
+```
+
+### Separate Server and Browser Setup
+
+Run FalkorDB server and browser as separate containers:
+
+```yaml
+version: '3.8'
+
+services:
+ falkordb-server:
+ image: falkordb/falkordb-server:latest
+ container_name: falkordb-server
+ ports:
+ - "6379:6379"
+ environment:
+ - REDIS_ARGS=--requirepass falkordb
+ - FALKORDB_ARGS=THREAD_COUNT 4
+ volumes:
+ - falkordb_data:/data
+ restart: unless-stopped
+ networks:
+ - falkordb-network
+
+ falkordb-browser:
+ image: falkordb/falkordb-browser:latest
+ container_name: falkordb-browser
+ ports:
+ - "3000:3000"
+ environment:
+ - FALKORDB_URL=redis://falkordb-server:6379
+ - FALKORDB_PASSWORD=falkordb
+ depends_on:
+ - falkordb-server
+ restart: unless-stopped
+ networks:
+ - falkordb-network
+
+volumes:
+ falkordb_data:
+ driver: local
+
+networks:
+ falkordb-network:
+ driver: bridge
+```
+
+### Complete Production Setup
+
+A comprehensive production-ready setup with all recommended configurations:
+
+```yaml
+version: '3.8'
+
+services:
+ falkordb:
+ image: falkordb/falkordb-server:latest
+ container_name: falkordb-production
+ ports:
+ - "6379:6379"
+ environment:
+ # Redis Configuration
+ - REDIS_ARGS=--requirepass ${FALKORDB_PASSWORD:-changeme} --appendonly yes --appendfsync everysec --maxmemory 2gb --maxmemory-policy allkeys-lru
+ # FalkorDB Configuration
+ - FALKORDB_ARGS=THREAD_COUNT 8 CACHE_SIZE 50 TIMEOUT_MAX 60000 TIMEOUT_DEFAULT 30000 QUERY_MEM_CAPACITY 104857600
+ volumes:
+ - falkordb_data:/data
+ - ./falkordb-config:/etc/falkordb
+ restart: unless-stopped
+ healthcheck:
+ test: ["CMD", "redis-cli", "-a", "$${FALKORDB_PASSWORD:-changeme}", "ping"]
+ interval: 30s
+ timeout: 10s
+ retries: 5
+ start_period: 30s
+ networks:
+ - falkordb-network
+ logging:
+ driver: "json-file"
+ options:
+ max-size: "10m"
+ max-file: "3"
+
+volumes:
+ falkordb_data:
+ driver: local
+
+networks:
+ falkordb-network:
+ driver: bridge
+```
+
+## Docker Compose Commands
+
+Common Docker Compose commands for managing FalkorDB:
+
+```bash
+# Start services in detached mode
+docker-compose up -d
+
+# View logs
+docker-compose logs -f
+
+# View logs for specific service
+docker-compose logs -f falkordb
+
+# Stop services
+docker-compose stop
+
+# Stop and remove containers
+docker-compose down
+
+# Stop and remove containers with volumes (WARNING: deletes data)
+docker-compose down -v
+
+# Restart services
+docker-compose restart
+
+# Check service status
+docker-compose ps
+
+# Execute commands in running container
+docker-compose exec falkordb redis-cli
+```
+
+## Environment Variables
+
+### REDIS_ARGS
+Pass arguments directly to the Redis server:
+
+```yaml
+environment:
+ - REDIS_ARGS=--requirepass mypassword --maxmemory 1gb --appendonly yes
+```
+
+Common Redis arguments:
+- `--requirepass ` - Set authentication password
+- `--appendonly yes` - Enable AOF persistence
+- `--appendfsync everysec` - AOF sync frequency
+- `--maxmemory ` - Maximum memory limit
+- `--maxmemory-policy ` - Eviction policy (e.g., `allkeys-lru`)
+
+### FALKORDB_ARGS
+Pass configuration to FalkorDB module:
+
+```yaml
+environment:
+ - FALKORDB_ARGS=THREAD_COUNT 4 CACHE_SIZE 25 TIMEOUT_MAX 10000
+```
+
+See the [Configuration](/getting-started/configuration) page for all available FalkorDB parameters.
+
+## Data Persistence
+
+### Using Named Volumes
+
+Named volumes are the recommended approach for data persistence:
+
+```yaml
+services:
+ falkordb:
+ image: falkordb/falkordb-server:latest
+ volumes:
+ - falkordb_data:/data
+
+volumes:
+ falkordb_data:
+```
+
+### Using Bind Mounts
+
+For specific host directory mapping:
+
+```yaml
+services:
+ falkordb:
+ image: falkordb/falkordb-server:latest
+ volumes:
+ - ./falkordb-data:/data
+```
+
+Create the directory first:
+
+```bash
+mkdir -p ./falkordb-data
+```
+
+## Health Checks
+
+Add health checks to ensure FalkorDB is running properly:
+
+```yaml
+healthcheck:
+ test: ["CMD", "redis-cli", "ping"]
+ interval: 30s
+ timeout: 10s
+ retries: 3
+ start_period: 40s
+```
+
+With authentication:
+
+```yaml
+healthcheck:
+ test: ["CMD", "redis-cli", "-a", "yourpassword", "ping"]
+ interval: 30s
+ timeout: 10s
+ retries: 3
+ start_period: 40s
+```
+
+## Networking
+
+### Custom Networks
+
+Create isolated networks for better security:
+
+```yaml
+networks:
+ falkordb-network:
+ driver: bridge
+ ipam:
+ config:
+ - subnet: 172.25.0.0/16
+```
+
+### Expose vs Ports
+
+Use `expose` for internal communication and `ports` for external access:
+
+```yaml
+services:
+ falkordb:
+ image: falkordb/falkordb-server:latest
+ expose:
+ - "6379" # Only accessible within Docker network
+ # Or use ports for external access:
+ # ports:
+ # - "6379:6379"
+```
+
+## Best Practices
+
+1. **Use Environment Variables**: Store sensitive information like passwords in `.env` files or environment variables:
+
+ Create a `.env` file:
+ ```
+ FALKORDB_PASSWORD=your-secure-password
+ FALKORDB_THREADS=8
+ ```
+
+ Reference in `docker-compose.yml`:
+ ```yaml
+ environment:
+ - REDIS_ARGS=--requirepass ${FALKORDB_PASSWORD}
+ - FALKORDB_ARGS=THREAD_COUNT ${FALKORDB_THREADS}
+ ```
+
+2. **Enable Persistence**: Always use volumes for production data:
+ ```yaml
+ volumes:
+ - falkordb_data:/data
+ ```
+
+3. **Set Resource Limits**: Prevent resource exhaustion:
+ ```yaml
+ deploy:
+ resources:
+ limits:
+ cpus: '4'
+ memory: 8G
+ reservations:
+ cpus: '2'
+ memory: 4G
+ ```
+
+4. **Use Health Checks**: Ensure automatic recovery:
+ ```yaml
+ healthcheck:
+ test: ["CMD", "redis-cli", "ping"]
+ interval: 30s
+ timeout: 10s
+ retries: 3
+ ```
+
+5. **Configure Logging**: Manage log file sizes:
+ ```yaml
+ logging:
+ driver: "json-file"
+ options:
+ max-size: "10m"
+ max-file: "3"
+ ```
+
+6. **Separate Concerns**: Use different images for different purposes:
+ - Development: `falkordb/falkordb` (with browser)
+ - Production: `falkordb/falkordb-server` (server only)
+
+7. **Use Specific Tags**: Pin to specific versions for stability:
+ ```yaml
+ image: falkordb/falkordb-server:4.0.0
+ ```
+
+## Troubleshooting
+
+### Check Container Logs
+
+```bash
+docker-compose logs falkordb
+```
+
+### Check Container Status
+
+```bash
+docker-compose ps
+```
+
+### Test Connection
+
+```bash
+docker-compose exec falkordb redis-cli ping
+```
+
+### Access Redis CLI
+
+```bash
+docker-compose exec falkordb redis-cli
+```
+
+### View Running Processes
+
+```bash
+docker-compose top
+```
+
+### Inspect Configuration
+
+```bash
+docker-compose config
+```
+
+## Next Steps
+
+- Learn about [Persistence](/operations/persistence) for data durability
+- Set up [Replication](/operations/replication) for high availability
+- Configure a [Cluster](/operations/cluster) for scalability
+- Review [Configuration](/getting-started/configuration) options
+- Deploy to [Kubernetes](/operations/k8s-support) for orchestration
diff --git a/operations/falkordblite.md b/operations/falkordblite.md
index 00f1c26e..11df1f5b 100644
--- a/operations/falkordblite.md
+++ b/operations/falkordblite.md
@@ -5,12 +5,10 @@ parent: Operations
description: "Self-contained Python interface to FalkorDB"
---
-# [EXPERIMENTAL] FalkorDBLite
+# FalkorDBLite
FalkorDBLite is a self-contained Python interface to the FalkorDB graph database. It provides an embedded Redis server with the FalkorDB module that is automatically installed, configured, and managed when the bindings are used.
-> **Note:** FalkorDBLite is an experimental feature. While it's functional and useful for development and testing, it's recommended to use a full FalkorDB deployment for production environments.
-
## Key Features
- **Easy to Use** - Built-in Redis server with FalkorDB module that is automatically installed, configured, and managed
@@ -23,7 +21,6 @@ FalkorDBLite is a self-contained Python interface to the FalkorDB graph database
## Requirements
- Python 3.12 or higher
-- System build tools (automatically handled during installation on most systems)
## Installation
@@ -36,38 +33,13 @@ pip install falkordblite
The package will automatically install its dependencies, including:
- `redis>=4.5` - Redis Python client
- `psutil` - Process and system utilities
-- `setuptools>38.0` - Build system
-
-### System Prerequisites
-
-#### Linux
-
-On Ubuntu/Debian systems:
-
-```bash
-apt-get install python3-dev build-essential
-```
-
-On Redhat/Fedora systems:
-
-```bash
-yum install python3-devel gcc make
-```
-
-#### macOS
-
-Install XCode command line utilities:
-
-```bash
-xcode-select --install
-```
-#### Windows
+### macOS Runtime Requirement
-FalkorDBLite can be installed on Windows 10 and later under the Windows Subsystem for Linux (WSL). Follow the [WSL installation guide](https://learn.microsoft.com/en-us/windows/wsl/install) and then install the python-dev package:
+**Important:** On macOS, the FalkorDB module requires the OpenMP runtime library (`libomp`). If you encounter an error like `Library not loaded: /opt/homebrew/opt/libomp/lib/libomp.dylib`, install it using Homebrew:
```bash
-apt-get install python-dev
+brew install libomp
```
## Getting Started
diff --git a/operations/index.md b/operations/index.md
index 16b89a47..dc2fcafe 100644
--- a/operations/index.md
+++ b/operations/index.md
@@ -2,6 +2,9 @@
title: "Operations"
nav_order: 10
description: "Configuring FalkorDB Docker"
+redirect_from:
+ - /operation
+ - /operation.html
---
# Operations
@@ -12,42 +15,46 @@ The Operations chapter provides essential guides for configuring and managing Fa
Table of Contents
-## 1. [Configuring Persistence](/operations/persistence)
+## 1. [Docker and Docker Compose](/operations/docker)
+
+Learn how to run FalkorDB using Docker and Docker Compose, with examples for development and production environments including persistence, networking, and configuration options.
+
+## 2. [Configuring Persistence](/operations/persistence)
Learn how to set up FalkorDB with data persistence, ensuring that your data remains intact even after server restarts.
-## 2. [Configuring Replication](/operations/replication)
+## 3. [Configuring Replication](/operations/replication)
Set up replication in FalkorDB to achieve high availability and data redundancy across multiple nodes.
-## 3. [Setting Up a Cluster](/operations/cluster)
+## 4. [Setting Up a Cluster](/operations/cluster)
Discover how to configure a FalkorDB cluster for horizontal scalability and improved fault tolerance, distributing your data across multiple nodes.
-## 4. [Deploy FalkorDB to Kubernetes](/operations/k8s_support)
+## 5. [Deploy FalkorDB to Kubernetes](/operations/k8s_support)
Learn how falkorDB can be deployed on Kubernetes using Helm charts and Docker images.
-## 5. [Deploy FalkorDB with KubeBlocks](/operations/kubeblocks)
+## 6. [Deploy FalkorDB with KubeBlocks](/operations/kubeblocks)
Deploy and manage FalkorDB on Kubernetes using the KubeBlocks operator with automated Day-2 operations, high availability, and comprehensive backup solutions.
-## 6. [Deploy FalkorDB on Railway](/operations/railway)
+## 7. [Deploy FalkorDB on Railway](/operations/railway)
Deploy FalkorDB quickly using verified templates on Railway, a modern platform-as-a-service. Choose between single instance or cluster deployments.
-## 7. [OpenTelemetry Integration with FalkorDB-py](/operations/opentelemetry)
+## 8. [OpenTelemetry Integration with FalkorDB-py](/operations/opentelemetry)
Comprehensive guide for setting up OpenTelemetry observability and tracing with FalkorDB Python applications.
-## 8. [FalkorDBLite](/operations/falkordblite)
+## 9. [FalkorDBLite](/operations/falkordblite)
Self-contained Python interface to FalkorDB with embedded Redis server, ideal for development and testing.
-## 9. [Deploy FalkorDB on Lightning.AI](/operations/lightning-ai)
+## 10. [Deploy FalkorDB on Lightning.AI](/operations/lightning-ai)
Deploy FalkorDB on Lightning.AI to build fast, accurate GenAI applications using advanced RAG with graph databases.
-## 10. [Building Docker](/operations/building-docker)
+## 11. [Building Docker](/operations/building-docker)
Build custom FalkorDB Docker containers from source with platform-specific examples.
diff --git a/operations/persistence.md b/operations/persistence.md
index f88bb32d..4af894e5 100644
--- a/operations/persistence.md
+++ b/operations/persistence.md
@@ -39,24 +39,31 @@ You can now run FalkorDB with the volume attached:
docker run -d --name falkordb -v falkordb_data:/var/lib/falkordb/data -p 6379:6379 falkordb/falkordb
```
-In this configuration:
-
-The -v falkordb_data:/var/lib/falkordb/data flag mounts the volume to the /var/lib/falkordb/data directory inside the container.
-FalkorDB will use the /var/lib/falkordb/data directory by default.
+**Configuration details:**
+- The `-v falkordb_data:/var/lib/falkordb/data` flag mounts the volume to the `/var/lib/falkordb/data` directory inside the container
+- FalkorDB stores its data in the `/var/lib/falkordb/data` directory by default
## Step 2: Verifying the Setup
-To verify that your setup is working correctly:
+To verify that persistence is working correctly, follow these steps:
-* Persistence Check: Stop the FalkorDB container and start it again. The data should persist across restarts.
+### 2.1 Create Test Data
```bash
-redis-cli graph.query mygraph "CREATE (:Database {name:'falkordb'})"
+redis-cli GRAPH.QUERY mygraph "CREATE (:Database {name:'falkordb'})"
+```
+
+### 2.2 Restart Container
+```bash
docker stop falkordb
docker start falkordb
+```
-redis-cli graph.query mygraph "MATCH (n) return n"
+### 2.3 Verify Data Persists
+
+```bash
+redis-cli GRAPH.QUERY mygraph "MATCH (n) RETURN n"
# Output should be:
# 1) 1) "n"
# 2) 1) 1) 1) 1) "id"
@@ -70,9 +77,15 @@ redis-cli graph.query mygraph "MATCH (n) return n"
# 2) "Query internal execution time: 0.122645 milliseconds"
```
-## Conclusion
+## Best Practices
+
+- **Backup Regularly:** Even with persistence, maintain regular backups of your data
+- **Monitor Disk Space:** Ensure sufficient disk space is available for the volume
+- **Use Named Volumes:** Named volumes are easier to manage than bind mounts
+
+## Next Steps
-With persistence configured, FalkorDB is now set up for reliable data storage that remains intact across container restarts. This setup ensures that your data is consistently saved, providing a stable and dependable environment for your applications.
+With persistence configured, FalkorDB is now set up for reliable data storage that remains intact across container restarts.
-If you're interested in learning more about high availability and replication, be sure to check out the [replication](/operations/replication) chapter in the documentation.
+For high availability and data redundancy, explore [Replication](/operations/replication) to set up multiple FalkorDB instances.
diff --git a/operations/replication.md b/operations/replication.md
index a2e8001e..b9c12776 100644
--- a/operations/replication.md
+++ b/operations/replication.md
@@ -3,6 +3,9 @@ title: "Replication"
nav_order: 2
description: "Configuring FalkorDB Docker for Replication"
parent: "Operations"
+redirect_from:
+ - /operation/replication
+ - /operation/replication.html
---
# Configuring FalkorDB Docker for Replication
@@ -19,8 +22,9 @@ Before you begin, ensure you have the following:
## Step 1: Configuring Replication
-Replication ensures that your data is available across multiple FalkorDB instances. You can configure one instance as the master and others as replicas.
-For that to work with Docker, we need to first set up a network.
+Replication ensures that your data is available across multiple FalkorDB instances. You configure one instance as the primary (master) and others as replicas.
+
+To enable communication between FalkorDB containers, we first need to set up a Docker network.
### 1.1 Creating a Network
@@ -43,7 +47,7 @@ docker run -d \
falkordb/falkordb
```
-This instance will be created in the Standalone mode, as master.
+This instance runs in standalone mode and will serve as the primary (master) node.
### 1.2 Setting up the Replica Instance
@@ -70,19 +74,23 @@ This command tells the replica to replicate data from the master instance.
## Step 2: Verifying the Setup
-To verify that your setup is working correctly:
+To verify that replication is working correctly:
-* Replication Check: Insert some data into the master instance and check if it is available in the replica.
+### 2.1 Insert Data on Master
```bash
# Connect to the master
-docker exec -it falkordb-master /bin/bash
-redis-cli graph.query mygraph "CREATE (:Database {name:'falkordb'})"
+docker exec -it falkordb-master redis-cli
+GRAPH.QUERY mygraph "CREATE (:Database {name:'falkordb'})"
exit
+```
+
+### 2.2 Verify Data on Replica
+```bash
# Connect to the replica
-docker exec -it falkordb-replica1 /bin/bash
-redis-cli graph.ro_query mygraph "MATCH (n) return n"
+docker exec -it falkordb-replica1 redis-cli
+GRAPH.RO_QUERY mygraph "MATCH (n) RETURN n"
# Output should be:
# 1) 1) "n"
# 2) 1) 1) 1) 1) "id"
@@ -96,8 +104,25 @@ redis-cli graph.ro_query mygraph "MATCH (n) return n"
# 2) "Query internal execution time: 0.122645 milliseconds"
```
-## Conclusion
+**Expected output:** The data created on the master should be available on the replica.
+
+## Best Practices
+
+- **Read-Only Queries on Replicas:** Use `GRAPH.RO_QUERY` for read operations on replicas to prevent accidental writes
+- **Monitor Replication Lag:** Check replication status regularly using Redis `INFO replication` command
+- **Multiple Replicas:** Configure multiple replicas for better read scalability and redundancy
+- **Network Latency:** Place master and replicas in the same network or region for optimal performance
+
+## Troubleshooting
+
+If replication is not working:
+
+1. Verify network connectivity between containers
+2. Check that the master is accessible from the replica
+3. Review logs for errors: `docker logs falkordb-replica1`
+
+## Next Steps
-With replication configured, FalkorDB is now set up for high availability and data redundancy, ensuring that your data is synchronized across multiple instances. This setup provides a robust and fault-tolerant environment for your applications.
+With replication configured, FalkorDB provides high availability and data redundancy. Your data is now synchronized across multiple instances, creating a robust and fault-tolerant environment.
-If you're interested in learning more about clustering and scaling out, be sure to check out the [Cluster](/operations/cluster) chapter in the documentation.
\ No newline at end of file
+For horizontal scalability and distributed graph operations, explore [Clustering](/operations/cluster).
diff --git a/udfs/flex/bitwise/and.md b/udfs/flex/bitwise/and.md
new file mode 100644
index 00000000..c5b0f91f
--- /dev/null
+++ b/udfs/flex/bitwise/and.md
@@ -0,0 +1,67 @@
+---
+layout: default
+title: bitwise.and
+parent: Bitwise Functions
+grand_parent: FLEX Function Reference
+---
+
+# bitwise.and
+
+## Description
+Performs a bitwise AND operation on two integers. Each bit in the result is 1 only if the corresponding bits in both operands are 1.
+
+## Syntax
+```cypher
+flex.bitwise.and(a, b)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `a` | number (integer) | Yes | First operand |
+| `b` | number (integer) | Yes | Second operand |
+
+## Returns
+**Type:** number (integer)
+
+The result of the bitwise AND operation.
+
+## Examples
+
+### Example 1: Basic AND Operation
+```cypher
+RETURN flex.bitwise.and(12, 10) AS result
+```
+
+**Output:**
+```
+result
+------
+8
+```
+(Binary: 1100 AND 1010 = 1000 = 8)
+
+### Example 2: Checking Permission Flags
+```cypher
+WITH 7 AS userPermissions // 0111 (read=1, write=2, execute=4)
+WITH userPermissions, 2 AS writeFlag
+RETURN flex.bitwise.and(userPermissions, writeFlag) > 0 AS hasWrite
+```
+
+### Example 3: Masking Bits
+```cypher
+MATCH (d:Device)
+WITH d, flex.bitwise.and(d.flags, 15) AS lowerNibble
+RETURN d.id, lowerNibble
+```
+
+## Notes
+- Operates on 32-bit signed integers in JavaScript
+- Both operands are converted to integers if needed
+- Commonly used for flag checking and bit masking
+
+## See Also
+- [bitwise.or](./or.md) - Bitwise OR operation
+- [bitwise.xor](./xor.md) - Bitwise XOR operation
+- [bitwise.not](./not.md) - Bitwise NOT operation
\ No newline at end of file
diff --git a/udfs/flex/bitwise/index.md b/udfs/flex/bitwise/index.md
new file mode 100644
index 00000000..e133a781
--- /dev/null
+++ b/udfs/flex/bitwise/index.md
@@ -0,0 +1,12 @@
+---
+layout: default
+title: Bitwise Functions
+parent: FLEX Function Reference
+grand_parent: UDFs
+has_children: true
+nav_order: 10
+---
+
+# Bitwise Functions
+
+FLEX bitwise utilities.
\ No newline at end of file
diff --git a/udfs/flex/bitwise/not.md b/udfs/flex/bitwise/not.md
new file mode 100644
index 00000000..5bfff347
--- /dev/null
+++ b/udfs/flex/bitwise/not.md
@@ -0,0 +1,80 @@
+---
+layout: default
+title: bitwise.not
+parent: Bitwise Functions
+grand_parent: FLEX Function Reference
+---
+
+# bitwise.not
+
+## Description
+Performs a bitwise NOT operation (one's complement) on an integer, inverting all bits.
+
+## Syntax
+```cypher
+flex.bitwise.not(a)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `a` | number (integer) | Yes | The operand to invert |
+
+## Returns
+**Type:** number (integer)
+
+The result of the bitwise NOT operation (one's complement).
+
+## Examples
+
+### Example 1: Basic NOT Operation
+```cypher
+RETURN flex.bitwise.not(5) AS result
+```
+
+**Output:**
+```
+result
+------
+-6
+```
+(Binary: NOT 0101 = ...11111010 in 32-bit two's complement = -6)
+
+### Example 2: Inverting All Bits
+```cypher
+RETURN flex.bitwise.not(0) AS result
+```
+
+**Output:**
+```
+result
+------
+-1
+```
+(All bits become 1 in two's complement = -1)
+
+### Example 3: Double NOT Returns Original
+```cypher
+WITH 42 AS value
+RETURN flex.bitwise.not(flex.bitwise.not(value)) AS restored
+```
+
+**Output:**
+```
+restored
+--------
+42
+```
+
+## Notes
+- Operates on 32-bit signed integers in JavaScript
+- Result uses two's complement representation
+- NOT operation inverts all bits including sign bit
+- Formula: `~n = -(n + 1)`
+- Less commonly used than AND, OR, XOR in typical applications
+
+## See Also
+- [bitwise.and](./and.md) - Bitwise AND operation
+- [bitwise.or](./or.md) - Bitwise OR operation
+- [bitwise.xor](./xor.md) - Bitwise XOR operation
\ No newline at end of file
diff --git a/udfs/flex/bitwise/or.md b/udfs/flex/bitwise/or.md
new file mode 100644
index 00000000..2125d1be
--- /dev/null
+++ b/udfs/flex/bitwise/or.md
@@ -0,0 +1,73 @@
+---
+layout: default
+title: bitwise.or
+parent: Bitwise Functions
+grand_parent: FLEX Function Reference
+---
+
+# bitwise.or
+
+## Description
+Performs a bitwise OR operation on two integers. Each bit in the result is 1 if at least one of the corresponding bits in the operands is 1.
+
+## Syntax
+```cypher
+flex.bitwise.or(a, b)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `a` | number (integer) | Yes | First operand |
+| `b` | number (integer) | Yes | Second operand |
+
+## Returns
+**Type:** number (integer)
+
+The result of the bitwise OR operation.
+
+## Examples
+
+### Example 1: Basic OR Operation
+```cypher
+RETURN flex.bitwise.or(12, 10) AS result
+```
+
+**Output:**
+```
+result
+------
+14
+```
+(Binary: 1100 OR 1010 = 1110 = 14)
+
+### Example 2: Combining Permission Flags
+```cypher
+WITH 1 AS readFlag, 2 AS writeFlag
+RETURN flex.bitwise.or(readFlag, writeFlag) AS readWritePermission
+```
+
+**Output:**
+```
+readWritePermission
+-------------------
+3
+```
+(Binary: 01 OR 10 = 11 = 3)
+
+### Example 3: Setting Multiple Flags
+```cypher
+MATCH (u:User {id: 123})
+SET u.permissions = flex.bitwise.or(u.permissions, 4) // Add execute permission
+```
+
+## Notes
+- Operates on 32-bit signed integers in JavaScript
+- Both operands are converted to integers if needed
+- Commonly used for combining flags and setting bits
+
+## See Also
+- [bitwise.and](./and.md) - Bitwise AND operation
+- [bitwise.xor](./xor.md) - Bitwise XOR operation
+- [bitwise.not](./not.md) - Bitwise NOT operation
\ No newline at end of file
diff --git a/udfs/flex/bitwise/shiftLeft.md b/udfs/flex/bitwise/shiftLeft.md
new file mode 100644
index 00000000..3c87225c
--- /dev/null
+++ b/udfs/flex/bitwise/shiftLeft.md
@@ -0,0 +1,85 @@
+---
+layout: default
+title: bitwise.shiftLeft
+parent: Bitwise Functions
+grand_parent: FLEX Function Reference
+---
+
+# bitwise.shiftLeft
+
+## Description
+Performs a left bit shift operation, moving all bits to the left by the specified number of positions. Zero bits are shifted in from the right.
+
+## Syntax
+```cypher
+flex.bitwise.shiftLeft(a, positions)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `a` | number (integer) | Yes | The value to shift |
+| `positions` | number (integer) | Yes | Number of positions to shift left |
+
+## Returns
+**Type:** number (integer)
+
+The result of shifting the bits left by the specified positions.
+
+## Examples
+
+### Example 1: Basic Left Shift
+```cypher
+RETURN flex.bitwise.shiftLeft(5, 2) AS result
+```
+
+**Output:**
+```
+result
+------
+20
+```
+(Binary: 0101 << 2 = 10100 = 20)
+
+### Example 2: Multiply by Power of Two
+```cypher
+WITH 7 AS value
+RETURN
+ flex.bitwise.shiftLeft(value, 1) AS times2,
+ flex.bitwise.shiftLeft(value, 2) AS times4,
+ flex.bitwise.shiftLeft(value, 3) AS times8
+```
+
+**Output:**
+```
+times2 | times4 | times8
+-------|--------|-------
+14 | 28 | 56
+```
+(Left shift by n is equivalent to multiplying by 2^n)
+
+### Example 3: Creating Bit Masks
+```cypher
+RETURN flex.bitwise.shiftLeft(1, 3) AS mask
+```
+
+**Output:**
+```
+mask
+----
+8
+```
+(Creates mask with bit 3 set: 1000)
+
+## Notes
+- Operates on 32-bit signed integers in JavaScript
+- Left shift by n is equivalent to multiplying by 2^n
+- Bits shifted off the left are discarded
+- Zero bits are shifted in from the right
+- Useful for multiplication by powers of 2 and creating bit masks
+
+## See Also
+- [bitwise.shiftRight](./shiftRight.md) - Shift bits to the right
+- [bitwise.and](./and.md) - Bitwise AND operation
+- [bitwise.or](./or.md) - Bitwise OR operation
\ No newline at end of file
diff --git a/udfs/flex/bitwise/shiftRight.md b/udfs/flex/bitwise/shiftRight.md
new file mode 100644
index 00000000..6fce7cc7
--- /dev/null
+++ b/udfs/flex/bitwise/shiftRight.md
@@ -0,0 +1,100 @@
+---
+layout: default
+title: bitwise.shiftRight
+parent: Bitwise Functions
+grand_parent: FLEX Function Reference
+---
+
+# bitwise.shiftRight
+
+## Description
+Performs a sign-propagating right bit shift operation, moving all bits to the right by the specified number of positions. The sign bit is copied to fill the leftmost positions.
+
+## Syntax
+```cypher
+flex.bitwise.shiftRight(a, positions)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `a` | number (integer) | Yes | The value to shift |
+| `positions` | number (integer) | Yes | Number of positions to shift right |
+
+## Returns
+**Type:** number (integer)
+
+The result of shifting the bits right by the specified positions, with sign extension.
+
+## Examples
+
+### Example 1: Basic Right Shift
+```cypher
+RETURN flex.bitwise.shiftRight(20, 2) AS result
+```
+
+**Output:**
+```
+result
+------
+5
+```
+(Binary: 10100 >> 2 = 00101 = 5)
+
+### Example 2: Divide by Power of Two
+```cypher
+WITH 56 AS value
+RETURN
+ flex.bitwise.shiftRight(value, 1) AS div2,
+ flex.bitwise.shiftRight(value, 2) AS div4,
+ flex.bitwise.shiftRight(value, 3) AS div8
+```
+
+**Output:**
+```
+div2 | div4 | div8
+-----|------|-----
+28 | 14 | 7
+```
+(Right shift by n is equivalent to integer division by 2^n)
+
+### Example 3: Sign Extension with Negative Numbers
+```cypher
+RETURN flex.bitwise.shiftRight(-8, 2) AS result
+```
+
+**Output:**
+```
+result
+------
+-2
+```
+(Sign bit is preserved in right shift)
+
+### Example 4: Extracting Higher Bits
+```cypher
+WITH 255 AS value // 11111111
+RETURN flex.bitwise.shiftRight(value, 4) AS upperNibble
+```
+
+**Output:**
+```
+upperNibble
+-----------
+15
+```
+(Extracts upper 4 bits: 00001111 = 15)
+
+## Notes
+- Operates on 32-bit signed integers in JavaScript
+- Uses arithmetic (sign-propagating) right shift
+- Right shift by n is equivalent to integer division by 2^n (truncated toward negative infinity)
+- Sign bit is copied to fill vacated positions (sign extension)
+- Bits shifted off the right are discarded
+- Useful for division by powers of 2 and extracting bit fields
+
+## See Also
+- [bitwise.shiftLeft](./shiftLeft.md) - Shift bits to the left
+- [bitwise.and](./and.md) - Bitwise AND operation
+- [bitwise.or](./or.md) - Bitwise OR operation
\ No newline at end of file
diff --git a/udfs/flex/bitwise/xor.md b/udfs/flex/bitwise/xor.md
new file mode 100644
index 00000000..9830c52e
--- /dev/null
+++ b/udfs/flex/bitwise/xor.md
@@ -0,0 +1,83 @@
+---
+layout: default
+title: bitwise.xor
+parent: Bitwise Functions
+grand_parent: FLEX Function Reference
+---
+
+# bitwise.xor
+
+## Description
+Performs a bitwise XOR (exclusive OR) operation on two integers. Each bit in the result is 1 if the corresponding bits in the operands are different.
+
+## Syntax
+```cypher
+flex.bitwise.xor(a, b)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `a` | number (integer) | Yes | First operand |
+| `b` | number (integer) | Yes | Second operand |
+
+## Returns
+**Type:** number (integer)
+
+The result of the bitwise XOR operation.
+
+## Examples
+
+### Example 1: Basic XOR Operation
+```cypher
+RETURN flex.bitwise.xor(12, 10) AS result
+```
+
+**Output:**
+```
+result
+------
+6
+```
+(Binary: 1100 XOR 1010 = 0110 = 6)
+
+### Example 2: Toggling Bits
+```cypher
+WITH 5 AS value, 3 AS toggleMask
+RETURN flex.bitwise.xor(value, toggleMask) AS toggled
+```
+
+**Output:**
+```
+toggled
+-------
+6
+```
+(Binary: 0101 XOR 0011 = 0110)
+
+### Example 3: Simple Encryption/Decryption
+```cypher
+WITH 42 AS data, 17 AS key
+WITH flex.bitwise.xor(data, key) AS encrypted
+RETURN flex.bitwise.xor(encrypted, key) AS decrypted
+```
+
+**Output:**
+```
+decrypted
+---------
+42
+```
+(XOR with same key twice returns original value)
+
+## Notes
+- Operates on 32-bit signed integers in JavaScript
+- Both operands are converted to integers if needed
+- XOR with same value twice returns the original value
+- Commonly used for toggling flags and simple encryption
+
+## See Also
+- [bitwise.and](./and.md) - Bitwise AND operation
+- [bitwise.or](./or.md) - Bitwise OR operation
+- [bitwise.not](./not.md) - Bitwise NOT operation
\ No newline at end of file
diff --git a/udfs/flex/collections/frequencies.md b/udfs/flex/collections/frequencies.md
new file mode 100644
index 00000000..89ec4ae9
--- /dev/null
+++ b/udfs/flex/collections/frequencies.md
@@ -0,0 +1,85 @@
+---
+layout: default
+title: coll.frequencies
+parent: Collection Functions
+grand_parent: FLEX Function Reference
+---
+
+# coll.frequencies
+
+## Description
+Counts the frequency of each element in a list, returning a map where keys are the unique elements and values are their occurrence counts.
+
+## Syntax
+```cypher
+flex.coll.frequencies(list)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `list` | list | Yes | The list to analyze |
+
+## Returns
+**Type:** map (object)
+
+A map where each key is a unique element from the list and each value is the count of how many times that element appears. Returns an empty map if input is not an array.
+
+## Examples
+
+### Example 1: Basic Frequency Count
+```cypher
+WITH ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple'] AS fruits
+RETURN flex.coll.frequencies(fruits) AS counts
+```
+
+**Output:**
+```
+counts
+---------------------------------------
+{apple: 3, banana: 2, cherry: 1}
+```
+
+### Example 2: Tag Analysis
+```cypher
+MATCH (d:Document)
+WITH collect(d.tags) AS allTagLists
+UNWIND allTagLists AS tags
+UNWIND tags AS tag
+WITH collect(tag) AS flatTags
+RETURN flex.coll.frequencies(flatTags) AS tagCounts
+```
+
+### Example 3: Finding Most Common Values
+```cypher
+MATCH (u:User)
+WITH collect(u.country) AS countries
+WITH flex.coll.frequencies(countries) AS freq
+UNWIND keys(freq) AS country
+RETURN country, freq[country] AS count
+ORDER BY count DESC
+LIMIT 10
+```
+
+### Example 4: Word Frequency Analysis
+```cypher
+MATCH (doc:Document)
+WITH split(toLower(doc.content), ' ') AS words
+WITH flex.coll.frequencies(words) AS wordCounts
+UNWIND keys(wordCounts) AS word
+WHERE wordCounts[word] > 5
+RETURN word, wordCounts[word] AS frequency
+ORDER BY frequency DESC
+```
+
+## Notes
+- Returns empty map if input is not an array or is `null`
+- `null` and `undefined` values are stored with key `"null"`
+- All elements are converted to string keys in the result map
+- Useful for analytics, statistics, and data exploration
+- Can be combined with `keys()` and sorting for top-N analysis
+
+## See Also
+- [coll.union](./union.md) - Get unique elements (keys would give unique items)
+- [coll.intersection](./intersection.md) - Find common elements
\ No newline at end of file
diff --git a/udfs/flex/collections/index.md b/udfs/flex/collections/index.md
new file mode 100644
index 00000000..b033c4b9
--- /dev/null
+++ b/udfs/flex/collections/index.md
@@ -0,0 +1,12 @@
+---
+layout: default
+title: Collection Functions
+parent: FLEX Function Reference
+grand_parent: UDFs
+has_children: true
+nav_order: 20
+---
+
+# Collection Functions
+
+FLEX collections utilities.
\ No newline at end of file
diff --git a/udfs/flex/collections/intersection.md b/udfs/flex/collections/intersection.md
new file mode 100644
index 00000000..64256b95
--- /dev/null
+++ b/udfs/flex/collections/intersection.md
@@ -0,0 +1,79 @@
+---
+layout: default
+title: coll.intersection
+parent: Collection Functions
+grand_parent: FLEX Function Reference
+---
+
+# coll.intersection
+
+## Description
+Finds the common elements between two lists, returning a new list containing only the elements that appear in both input lists.
+
+## Syntax
+```cypher
+flex.coll.intersection(list1, list2)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `list1` | list | Yes | The first list |
+| `list2` | list | Yes | The second list |
+
+## Returns
+**Type:** list
+
+A new list containing only the elements that exist in both input lists. Preserves the order from the first list.
+
+## Examples
+
+### Example 1: Basic Intersection
+```cypher
+WITH [1, 2, 3, 4] AS a, [3, 4, 5, 6] AS b
+RETURN flex.coll.intersection(a, b) AS result
+```
+
+**Output:**
+```
+result
+-------
+[3, 4]
+```
+
+### Example 2: Finding Common Tags
+```cypher
+MATCH (d1:Document {id: 'doc1'})
+MATCH (d2:Document {id: 'doc2'})
+WITH flex.coll.intersection(d1.tags, d2.tags) AS commonTags
+WHERE size(commonTags) > 0
+RETURN commonTags
+```
+
+### Example 3: Finding Users with Shared Interests
+```cypher
+MATCH (u1:User {id: $userId1})
+MATCH (u2:User {id: $userId2})
+WITH flex.coll.intersection(u1.interests, u2.interests) AS sharedInterests
+RETURN u1.name, u2.name, sharedInterests, size(sharedInterests) AS commonCount
+```
+
+### Example 4: Filter by Allowed Values
+```cypher
+WITH ['admin', 'read', 'write', 'delete'] AS allowed
+MATCH (u:User)
+WITH u, flex.coll.intersection(u.permissions, allowed) AS validPerms
+RETURN u.name, validPerms
+```
+
+## Notes
+- Returns elements that exist in both lists
+- Preserves the order from the first list
+- If an element appears multiple times in list1, each occurrence is checked against list2
+- Efficient implementation using Set for fast lookup
+- Equivalent to mathematical set intersection operation
+
+## See Also
+- [coll.union](./union.md) - Combine all unique elements from both lists
+- [sim.jaccard](../similarity/jaccard.md) - Calculate similarity coefficient using intersection
\ No newline at end of file
diff --git a/udfs/flex/collections/shuffle.md b/udfs/flex/collections/shuffle.md
new file mode 100644
index 00000000..e810e8e8
--- /dev/null
+++ b/udfs/flex/collections/shuffle.md
@@ -0,0 +1,77 @@
+---
+layout: default
+title: coll.shuffle
+parent: Collection Functions
+grand_parent: FLEX Function Reference
+---
+
+# coll.shuffle
+
+## Description
+Randomly shuffles the elements of a list using the Fisher-Yates algorithm. Returns a new list with elements in random order without modifying the original.
+
+## Syntax
+```cypher
+flex.coll.shuffle(list)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `list` | list | Yes | The list to shuffle |
+
+## Returns
+**Type:** list
+
+A new list containing the same elements in a randomized order. Returns an empty list if input is not an array.
+
+## Examples
+
+### Example 1: Basic Shuffle
+```cypher
+WITH [1, 2, 3, 4, 5] AS numbers
+RETURN flex.coll.shuffle(numbers) AS shuffled
+```
+
+**Output:** (example, actual order will vary)
+```
+shuffled
+-----------
+[3, 1, 5, 2, 4]
+```
+
+### Example 2: Random Sample Selection
+```cypher
+MATCH (q:Question)
+WITH collect(q) AS allQuestions
+WITH flex.coll.shuffle(allQuestions) AS randomized
+RETURN randomized[0..10] AS quizQuestions
+```
+
+### Example 3: Randomizing Recommendations
+```cypher
+MATCH (u:User {id: $userId})-[:LIKES]->(p:Product)
+MATCH (p)-[:SIMILAR_TO]->(rec:Product)
+WITH collect(DISTINCT rec) AS recommendations
+RETURN flex.coll.shuffle(recommendations)[0..5] AS randomRecs
+```
+
+### Example 4: Random Team Assignment
+```cypher
+MATCH (p:Player)
+WITH collect(p.name) AS players
+WITH flex.coll.shuffle(players) AS shuffled
+RETURN shuffled[0..5] AS team1, shuffled[5..10] AS team2
+```
+
+## Notes
+- Returns empty list if input is not an array or is `null`
+- Uses the Fisher-Yates shuffle algorithm for uniform random distribution
+- Creates a new list; does not modify the original
+- Each element appears exactly once in the result
+- Order is truly random on each execution
+
+## See Also
+- [coll.zip](./zip.md) - Combine two lists element-by-element
+- [coll.union](./union.md) - Combine unique elements from lists
\ No newline at end of file
diff --git a/udfs/flex/collections/union.md b/udfs/flex/collections/union.md
new file mode 100644
index 00000000..030312cc
--- /dev/null
+++ b/udfs/flex/collections/union.md
@@ -0,0 +1,77 @@
+---
+layout: default
+title: coll.union
+parent: Collection Functions
+grand_parent: FLEX Function Reference
+---
+
+# coll.union
+
+## Description
+Combines two lists and returns a new list containing all unique elements from both lists. Duplicates are automatically removed, treating the inputs as sets.
+
+## Syntax
+```cypher
+flex.coll.union(list1, list2)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `list1` | list | Yes | The first list |
+| `list2` | list | Yes | The second list |
+
+## Returns
+**Type:** list
+
+A new list containing all unique elements from both input lists. The order is not guaranteed.
+
+## Examples
+
+### Example 1: Basic Union
+```cypher
+WITH [1, 2, 3] AS a, [3, 4, 5] AS b
+RETURN flex.coll.union(a, b) AS result
+```
+
+**Output:**
+```
+result
+--------------
+[1, 2, 3, 4, 5]
+```
+
+### Example 2: Combining Tags from Multiple Nodes
+```cypher
+MATCH (d1:Document {id: 'doc1'})
+MATCH (d2:Document {id: 'doc2'})
+RETURN flex.coll.union(d1.tags, d2.tags) AS allTags
+```
+
+### Example 3: Merging User Interests
+```cypher
+MATCH (u:User)
+WITH collect(u.interests) AS interestLists
+RETURN reduce(result = [], list IN interestLists |
+ flex.coll.union(result, list)
+) AS allUniqueInterests
+```
+
+### Example 4: Finding All Related Categories
+```cypher
+MATCH (p:Product {id: 123})
+MATCH (similar:Product)-[:SIMILAR_TO]-(p)
+RETURN flex.coll.union(p.categories, similar.categories) AS combinedCategories
+```
+
+## Notes
+- Automatically removes duplicates from the result
+- Works with any comparable data types
+- Order of elements in the result is not guaranteed
+- Equivalent to mathematical set union operation
+- Both lists are spread and deduplicated using Set
+
+## See Also
+- [coll.intersection](./intersection.md) - Find common elements between lists
+- [sim.jaccard](../similarity/jaccard.md) - Calculate similarity between sets
\ No newline at end of file
diff --git a/udfs/flex/collections/zip.md b/udfs/flex/collections/zip.md
new file mode 100644
index 00000000..733e2045
--- /dev/null
+++ b/udfs/flex/collections/zip.md
@@ -0,0 +1,81 @@
+---
+layout: default
+title: coll.zip
+parent: Collection Functions
+grand_parent: FLEX Function Reference
+---
+
+# coll.zip
+
+## Description
+Combines two lists element-by-element into a list of pairs. Each pair contains one element from the first list and the corresponding element from the second list. The resulting list has the length of the shorter input list.
+
+## Syntax
+```cypher
+flex.coll.zip(list1, list2)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `list1` | list | Yes | The first list |
+| `list2` | list | Yes | The second list |
+
+## Returns
+**Type:** list of lists
+
+A list where each element is a two-element array `[item1, item2]` combining corresponding elements from both lists. Returns an empty list if either input is not an array.
+
+## Examples
+
+### Example 1: Basic Zipping
+```cypher
+WITH ['a', 'b', 'c'] AS letters, [1, 2, 3] AS numbers
+RETURN flex.coll.zip(letters, numbers) AS pairs
+```
+
+**Output:**
+```
+pairs
+----------------------------
+[["a", 1], ["b", 2], ["c", 3]]
+```
+
+### Example 2: Different Length Lists
+```cypher
+WITH ['x', 'y', 'z'] AS keys, [10, 20] AS values
+RETURN flex.coll.zip(keys, values) AS result
+```
+
+**Output:**
+```
+result
+--------------------
+[["x", 10], ["y", 20]]
+```
+(Only pairs up to the length of the shorter list)
+
+### Example 3: Creating Key-Value Pairs
+```cypher
+MATCH (p:Product)
+WITH collect(p.name) AS names, collect(p.price) AS prices
+RETURN flex.coll.zip(names, prices) AS productData
+```
+
+### Example 4: Pairing Related Data
+```cypher
+WITH ['Mon', 'Tue', 'Wed'] AS days, [120, 135, 98] AS sales
+UNWIND flex.coll.zip(days, sales) AS pair
+RETURN pair[0] AS day, pair[1] AS salesAmount
+```
+
+## Notes
+- Returns empty list if either input is not an array or is `null`
+- Result length is limited by the shorter of the two input lists
+- Excess elements from the longer list are ignored
+- Useful for pairing related data or creating key-value associations
+
+## See Also
+- [map.fromPairs](../map/fromPairs.md) - Convert pairs to a map
+- [coll.union](./union.md) - Combine lists as sets
\ No newline at end of file
diff --git a/udfs/flex/date/format.md b/udfs/flex/date/format.md
new file mode 100644
index 00000000..adba0d14
--- /dev/null
+++ b/udfs/flex/date/format.md
@@ -0,0 +1,102 @@
+---
+layout: default
+title: date.format
+parent: Date Functions
+grand_parent: FLEX Function Reference
+---
+
+# date.format
+
+## Description
+Formats a date/time value using a simple token-based pattern. Supports common date/time tokens and optional timezone offset adjustment.
+
+## Syntax
+```cypher
+flex.date.format(datetime, pattern, timezone)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `datetime` | Date/number/string | Yes | The date/time value to format |
+| `pattern` | string | No | Format pattern using tokens (default: `'YYYY-MM-DDTHH:mm:ss[Z]'`) |
+| `timezone` | string | No | Timezone offset like `"+02:00"` or `"-05:00"` |
+
+### Supported Pattern Tokens
+| Token | Description | Example |
+|-------|-------------|---------|
+| `YYYY` | 4-digit year | `2024` |
+| `MM` | 2-digit month (01-12) | `03` |
+| `DD` | 2-digit day (01-31) | `15` |
+| `HH` | 2-digit hour (00-23) | `14` |
+| `mm` | 2-digit minute (00-59) | `30` |
+| `ss` | 2-digit second (00-59) | `45` |
+| `SSS` | 3-digit milliseconds | `123` |
+| `[Z]` | Literal 'Z' character | `Z` |
+
+## Returns
+**Type:** string
+
+A formatted date/time string according to the pattern. Returns `null` if the input date is invalid.
+
+## Examples
+
+### Example 1: Basic Date Formatting
+```cypher
+WITH datetime('2024-03-15T14:30:00Z') AS dt
+RETURN flex.date.format(dt, 'YYYY-MM-DD') AS date
+```
+
+**Output:**
+```
+date
+----------
+2024-03-15
+```
+
+### Example 2: Full DateTime with Time
+```cypher
+WITH datetime('2024-03-15T14:30:45Z') AS dt
+RETURN flex.date.format(dt, 'YYYY-MM-DD HH:mm:ss') AS formatted
+```
+
+**Output:**
+```
+formatted
+-------------------
+2024-03-15 14:30:45
+```
+
+### Example 3: Custom Format with Timezone
+```cypher
+WITH datetime('2024-03-15T14:30:00Z') AS dt
+RETURN flex.date.format(dt, 'DD/MM/YYYY HH:mm', '+02:00') AS localTime
+```
+
+**Output:**
+```
+localTime
+-----------------
+15/03/2024 16:30
+```
+(Adjusted for +02:00 timezone)
+
+### Example 4: Formatting Node Timestamps
+```cypher
+MATCH (e:Event)
+RETURN e.name, flex.date.format(e.timestamp, 'YYYY-MM-DD') AS eventDate
+ORDER BY e.timestamp DESC
+```
+
+## Notes
+- Returns `null` for invalid date inputs
+- Default pattern is ISO8601-like: `'YYYY-MM-DDTHH:mm:ss[Z]'`
+- Timezone parameter adjusts the displayed time for the given offset
+- All calculations are UTC-based internally
+- Milliseconds are optional in the pattern
+
+## See Also
+- [date.parse](./parse.md) - Parse string to date
+- [date.truncate](./truncate.md) - Truncate date to specific unit
+- [date.toTimeZone](./toTimeZone.md) - Convert date to timezone
\ No newline at end of file
diff --git a/udfs/flex/date/index.md b/udfs/flex/date/index.md
new file mode 100644
index 00000000..997b02ec
--- /dev/null
+++ b/udfs/flex/date/index.md
@@ -0,0 +1,12 @@
+---
+layout: default
+title: Date Functions
+parent: FLEX Function Reference
+grand_parent: UDFs
+has_children: true
+nav_order: 30
+---
+
+# Date Functions
+
+FLEX date utilities.
\ No newline at end of file
diff --git a/udfs/flex/date/parse.md b/udfs/flex/date/parse.md
new file mode 100644
index 00000000..b017e2aa
--- /dev/null
+++ b/udfs/flex/date/parse.md
@@ -0,0 +1,81 @@
+---
+layout: default
+title: date.parse
+parent: Date Functions
+grand_parent: FLEX Function Reference
+---
+
+# date.parse
+
+## Description
+Parses a date/time string into a Date object using an optional pattern. Supports explicit patterns and falls back to standard Date parsing for other formats.
+
+## Syntax
+```cypher
+flex.date.parse(dateString, pattern, timezone)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `dateString` | string | Yes | The date/time string to parse |
+| `pattern` | string | No | Format pattern (supported: `'YYYY-MM-DD'`, `'YYYY-MM-DDTHH:mm:ss'` or `'YYYY-MM-DD HH:mm:ss'`, or auto-detect) |
+| `timezone` | string | No | Timezone offset like `"+02:00"` to interpret input in specific timezone |
+
+## Returns
+**Type:** Date
+
+A Date object representing the parsed date/time. Returns `null` if parsing fails.
+
+## Examples
+
+### Example 1: Parse Date Only
+```cypher
+RETURN flex.date.parse('2024-03-15', 'YYYY-MM-DD') AS date
+```
+
+**Output:**
+```
+date
+-----------------------------
+2024-03-15T00:00:00.000Z (Date object)
+```
+
+### Example 2: Parse DateTime
+```cypher
+RETURN flex.date.parse('2024-03-15T14:30:00', 'YYYY-MM-DDTHH:mm:ss') AS datetime
+```
+
+### Example 3: Auto-detect ISO Format
+```cypher
+RETURN flex.date.parse('2024-03-15T14:30:00Z') AS dt
+```
+
+### Example 4: Parse with Timezone Context
+```cypher
+WITH '2024-03-15 10:00:00' AS localTime
+RETURN flex.date.parse(localTime, 'YYYY-MM-DDTHH:mm:ss', '+05:00') AS utcTime
+```
+(Interprets input as being in +05:00 timezone and converts to UTC)
+
+### Example 5: Batch Import with Date Parsing
+```cypher
+UNWIND $events AS event
+CREATE (e:Event {
+ name: event.name,
+ date: flex.date.parse(event.dateString, 'YYYY-MM-DD')
+})
+```
+
+## Notes
+- Returns `null` for invalid or unparseable date strings
+- Supported explicit patterns: `'YYYY-MM-DD'`, `'YYYY-MM-DDTHH:mm:ss'` and `'YYYY-MM-DD HH:mm:ss'` (both `T` and space separators are accepted)
+- Falls back to JavaScript Date constructor for other formats (ISO8601, etc.)
+- Timezone parameter interprets the input time as local time in that offset
+- All dates are normalized to UTC internally
+
+## See Also
+- [date.format](./format.md) - Format date to string
+- [date.truncate](./truncate.md) - Truncate date to specific unit
+- [date.toTimeZone](./toTimeZone.md) - Convert date to timezone
\ No newline at end of file
diff --git a/udfs/flex/date/toTimeZone.md b/udfs/flex/date/toTimeZone.md
new file mode 100644
index 00000000..0de4012c
--- /dev/null
+++ b/udfs/flex/date/toTimeZone.md
@@ -0,0 +1,86 @@
+---
+layout: default
+title: date.toTimeZone
+parent: Date Functions
+grand_parent: FLEX Function Reference
+---
+
+# date.toTimeZone
+
+## Description
+Converts a date/time instant to represent the wall clock time in a given timezone offset. The returned Date represents the same instant but shifted so UTC fields reflect local time.
+
+## Syntax
+```cypher
+flex.date.toTimeZone(datetime, timezone)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `datetime` | Date/number/string | Yes | The date/time value to convert |
+| `timezone` | string | Yes | Timezone offset like `"+02:00"`, `"-05:00"`, or `"+0530"` |
+
+## Returns
+**Type:** Date
+
+A Date object adjusted to show local time in the given timezone. Returns `null` if input is invalid. Returns original date if timezone format is invalid.
+
+## Examples
+
+### Example 1: Convert UTC to Eastern Time
+```cypher
+WITH datetime('2024-03-15T14:00:00Z') AS utc
+RETURN flex.date.toTimeZone(utc, '-05:00') AS eastern
+```
+
+**Output:**
+```
+eastern
+--------------------------
+2024-03-15T09:00:00.000Z
+```
+(UTC fields now show 09:00 which is the local time in -05:00)
+
+### Example 2: Convert to Multiple Time Zones
+```cypher
+WITH datetime('2024-03-15T12:00:00Z') AS utc
+RETURN
+ flex.date.format(utc, 'HH:mm') AS utcTime,
+ flex.date.format(flex.date.toTimeZone(utc, '+00:00'), 'HH:mm') AS london,
+ flex.date.format(flex.date.toTimeZone(utc, '+01:00'), 'HH:mm') AS paris,
+ flex.date.format(flex.date.toTimeZone(utc, '+05:30'), 'HH:mm') AS india,
+ flex.date.format(flex.date.toTimeZone(utc, '-05:00'), 'HH:mm') AS newYork
+```
+
+### Example 3: Display User Events in Local Time
+```cypher
+MATCH (u:User {id: $userId})
+MATCH (e:Event)-[:ASSIGNED_TO]->(u)
+WITH e, flex.date.toTimeZone(e.timestamp, u.timezone) AS localTime
+RETURN e.name, flex.date.format(localTime, 'YYYY-MM-DD HH:mm') AS localDisplay
+ORDER BY e.timestamp
+```
+
+### Example 4: Adjust for Daylight Saving Time Context
+```cypher
+WITH datetime('2024-07-15T12:00:00Z') AS summer
+RETURN flex.date.format(
+ flex.date.toTimeZone(summer, '-04:00'),
+ 'YYYY-MM-DD HH:mm'
+) AS edtTime
+```
+
+## Notes
+- Returns `null` for invalid date inputs
+- Invalid timezone format returns the original date unchanged
+- Timezone format accepts `+HH:MM`, `-HH:MM`, `+HHMM`, or `-HHMM`
+- Does not handle DST transitions automatically
+- The returned Date's UTC methods will show the local time
+- Useful for displaying times in user's local timezone
+
+## See Also
+- [date.format](./format.md) - Format date with timezone support
+- [date.parse](./parse.md) - Parse date with timezone context
+- [date.truncate](./truncate.md) - Truncate date to specific unit
\ No newline at end of file
diff --git a/udfs/flex/date/truncate.md b/udfs/flex/date/truncate.md
new file mode 100644
index 00000000..c7127c47
--- /dev/null
+++ b/udfs/flex/date/truncate.md
@@ -0,0 +1,104 @@
+---
+layout: default
+title: date.truncate
+parent: Date Functions
+grand_parent: FLEX Function Reference
+---
+
+# date.truncate
+
+## Description
+Truncates a date/time value to the specified unit (e.g., day, month, year), setting all smaller units to their minimum values. All operations are UTC-based.
+
+## Syntax
+```cypher
+flex.date.truncate(datetime, unit)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `datetime` | Date/number/string | Yes | The date/time value to truncate |
+| `unit` | string | Yes | The unit to truncate to |
+
+### Supported Units
+| Unit | Description | Truncates To |
+|------|-------------|--------------|
+| `'minute'` | Truncate to start of minute | Sets seconds and milliseconds to 0 |
+| `'hour'` | Truncate to start of hour | Sets minutes, seconds, and milliseconds to 0 |
+| `'day'` | Truncate to start of day | Sets time to 00:00:00.000 |
+| `'week'` | Truncate to start of week | Sets to Monday 00:00:00.000 |
+| `'month'` | Truncate to start of month | Sets to 1st day at 00:00:00.000 |
+| `'quarter'` | Truncate to start of quarter | Sets to 1st day of quarter month at 00:00:00.000 |
+| `'year'` | Truncate to start of year | Sets to January 1st at 00:00:00.000 |
+
+## Returns
+**Type:** Date
+
+A new Date object truncated to the specified unit. Returns `null` if input is invalid. Returns the original date if unit is unrecognized.
+
+## Examples
+
+### Example 1: Truncate to Day
+```cypher
+WITH datetime('2024-03-15T14:30:45Z') AS dt
+RETURN flex.date.truncate(dt, 'day') AS truncated
+```
+
+**Output:**
+```
+truncated
+--------------------------
+2024-03-15T00:00:00.000Z
+```
+
+### Example 2: Truncate to Month
+```cypher
+WITH datetime('2024-03-15T14:30:45Z') AS dt
+RETURN flex.date.truncate(dt, 'month') AS truncated
+```
+
+**Output:**
+```
+truncated
+--------------------------
+2024-03-01T00:00:00.000Z
+```
+
+### Example 3: Group Events by Week
+```cypher
+MATCH (e:Event)
+WITH flex.date.truncate(e.timestamp, 'week') AS week, count(*) AS eventCount
+RETURN week, eventCount
+ORDER BY week
+```
+
+### Example 4: Monthly Aggregation
+```cypher
+MATCH (s:Sale)
+WITH flex.date.truncate(s.date, 'month') AS month, sum(s.amount) AS totalSales
+RETURN month, totalSales
+ORDER BY month
+```
+
+### Example 5: Quarter Analysis
+```cypher
+MATCH (o:Order)
+WITH flex.date.truncate(o.orderDate, 'quarter') AS quarter, count(*) AS orders
+RETURN quarter, orders
+ORDER BY quarter DESC
+```
+
+## Notes
+- Returns `null` for invalid date inputs
+- All operations use UTC timezone
+- Week starts on Monday (ISO week convention)
+- Quarters: Q1 (Jan-Mar), Q2 (Apr-Jun), Q3 (Jul-Sep), Q4 (Oct-Dec)
+- Unknown units return the original normalized date
+- Useful for time-series aggregation and bucketing
+
+## See Also
+- [date.format](./format.md) - Format date to string
+- [date.parse](./parse.md) - Parse string to date
+- [date.toTimeZone](./toTimeZone.md) - Convert date to timezone
\ No newline at end of file
diff --git a/udfs/flex/index.md b/udfs/flex/index.md
new file mode 100644
index 00000000..17940766
--- /dev/null
+++ b/udfs/flex/index.md
@@ -0,0 +1,137 @@
+---
+layout: default
+title: FLEX Function Reference
+parent: UDFs
+has_children: true
+---
+
+# FLEX Function Reference
+
+FLEX is FalkorDB's open source community UDF package, available at [github.com/FalkorDB/flex](https://github.com/FalkorDB/flex).
+It contains a variety of useful functionality, including:
+
+- String and set similarity metrics for fuzzy matching and comparison
+- Date and time manipulation, formatting, and parsing
+- Low-level bitwise operations on integers
+
+We welcome contributions to extend this library with additional functionality.
+
+The following sections document all FLEX (FalkorDB Library for Extensions) functions.
+
+## Function Categories
+
+### Similarity Functions (`flex.sim.*`)
+
+Set similarity metrics for fuzzy matching and comparison.
+
+| Function | Description |
+|----------|-------------|
+| [sim.jaccard](./similarity/jaccard.md) | Calculate Jaccard similarity coefficient between sets |
+
+### Text Functions (`flex.text.*`)
+
+String manipulation, formatting, case conversion utilities, and string similarity metrics.
+
+| Function | Description |
+|----------|-------------|
+| [text.capitalize](./text/capitalize.md) | Capitalize the first character of a string |
+| [text.decapitalize](./text/decapitalize.md) | Lowercase the first character of a string |
+| [text.swapCase](./text/swapCase.md) | Swap the case of all characters in a string |
+| [text.camelCase](./text/camelCase.md) | Convert string to camelCase format |
+| [text.upperCamelCase](./text/upperCamelCase.md) | Convert string to UpperCamelCase (PascalCase) |
+| [text.snakeCase](./text/snakeCase.md) | Convert string to snake_case format |
+| [text.format](./text/format.md) | Format string with placeholder substitution |
+| [text.indexOf](./text/indexOf.md) | Find first occurrence of substring |
+| [text.indexesOf](./text/indexesOf.md) | Find all occurrences of substring |
+| [text.join](./text/join.md) | Join array elements with delimiter |
+| [text.lpad](./text/lpad.md) | Pad string on the left to target length |
+| [text.rpad](./text/rpad.md) | Pad string on the right to target length |
+| [text.regexGroups](./text/regexGroups.md) | Extract regex matches and capture groups |
+| [text.repeat](./text/repeat.md) | Repeat string multiple times |
+| [text.replace](./text/replace.md) | Replace text using regex pattern |
+| [text.jaroWinkler](./text/jaroWinkler.md) | Compute Jaro-Winkler similarity for short strings |
+| [text.levenshtein](./text/levenshtein.md) | Compute Levenshtein edit distance between strings |
+
+### Collection Functions (`flex.coll.*`)
+
+Operations on lists and arrays including set operations and transformations.
+
+| Function | Description |
+|----------|-------------|
+| [coll.zip](./collections/zip.md) | Combine two lists element-by-element into pairs |
+| [coll.union](./collections/union.md) | Combine lists and return unique elements |
+| [coll.intersection](./collections/intersection.md) | Find common elements between lists |
+| [coll.shuffle](./collections/shuffle.md) | Randomly shuffle list elements |
+| [coll.frequencies](./collections/frequencies.md) | Count frequency of each element in list |
+
+### Map Functions (`flex.map.*`)
+
+Map/object manipulation for property management and transformation.
+
+| Function | Description |
+|----------|-------------|
+| [map.merge](./map/merge.md) | Shallow merge multiple maps |
+| [map.fromPairs](./map/fromPairs.md) | Convert list of key-value pairs to map |
+| [map.submap](./map/submap.md) | Extract subset of keys from map |
+| [map.removeKey](./map/removeKey.md) | Remove single key from map |
+| [map.removeKeys](./map/removeKeys.md) | Remove multiple keys from map |
+
+### JSON Functions (`flex.json.*`)
+
+JSON serialization and parsing utilities.
+
+| Function | Description |
+|----------|-------------|
+| [json.toJson](./json/toJson.md) | Serialize value to JSON string |
+| [json.fromJsonMap](./json/fromJsonMap.md) | Parse JSON string to map |
+| [json.fromJsonList](./json/fromJsonList.md) | Parse JSON string to list |
+
+### Date Functions (`flex.date.*`)
+
+Date and time manipulation, formatting, and parsing.
+
+| Function | Description |
+|----------|-------------|
+| [date.format](./date/format.md) | Format date/time with pattern and timezone |
+| [date.parse](./date/parse.md) | Parse date/time string with optional pattern |
+| [date.truncate](./date/truncate.md) | Truncate date to specific unit (day, month, etc.) |
+| [date.toTimeZone](./date/toTimeZone.md) | Convert date to timezone offset |
+
+### Bitwise Functions (`flex.bitwise.*`)
+
+Low-level bitwise operations on integers.
+
+| Function | Description |
+|----------|-------------|
+| [bitwise.and](./bitwise/and.md) | Bitwise AND operation |
+| [bitwise.or](./bitwise/or.md) | Bitwise OR operation |
+| [bitwise.xor](./bitwise/xor.md) | Bitwise XOR (exclusive OR) operation |
+| [bitwise.not](./bitwise/not.md) | Bitwise NOT (one's complement) operation |
+| [bitwise.shiftLeft](./bitwise/shiftLeft.md) | Left bit shift operation |
+| [bitwise.shiftRight](./bitwise/shiftRight.md) | Right bit shift with sign extension |
+
+## Common Use Cases
+
+### Data Cleaning and Normalization
+- `text.camelCase`, `text.snakeCase` - Normalize field names
+- `text.replace` - Remove or sanitize unwanted characters
+- `coll.union` - Deduplicate lists
+
+### Fuzzy Matching and Search
+- `text.levenshtein` - Find similar strings with edit distance
+- `text.jaroWinkler` - Match names and short strings
+- `sim.jaccard` - Compare sets and tag similarity
+
+### Data Aggregation and Analysis
+- `date.truncate` - Group by time periods
+- `coll.frequencies` - Count occurrences
+- `map.submap` - Select relevant fields
+
+### API and Data Exchange
+- `json.toJson`, `json.fromJsonMap` - JSON serialization
+- `map.removeKeys` - Filter sensitive data
+- `text.format` - Build formatted messages
+
+### Permission and Flag Management
+- `bitwise.and`, `bitwise.or` - Check and set permission flags
+- `bitwise.xor` - Toggle flags
diff --git a/udfs/flex/json/fromJsonList.md b/udfs/flex/json/fromJsonList.md
new file mode 100644
index 00000000..d8df3e9d
--- /dev/null
+++ b/udfs/flex/json/fromJsonList.md
@@ -0,0 +1,83 @@
+---
+layout: default
+title: json.fromJsonList
+parent: JSON Functions
+grand_parent: FLEX Function Reference
+---
+
+# json.fromJsonList
+
+## Description
+Parses a JSON string and returns it as a list (array). Safely handles malformed JSON by returning an empty list on parse errors.
+
+## Syntax
+```cypher
+flex.json.fromJsonList(jsonString)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `jsonString` | string | Yes | A JSON string representing an array |
+
+## Returns
+**Type:** list
+
+A list parsed from the JSON string. Returns an empty list `[]` if parsing fails or if the input is not a valid JSON array.
+
+## Examples
+
+### Example 1: Basic JSON Array Parsing
+```cypher
+WITH '[1, 2, 3, 4, 5]' AS json
+RETURN flex.json.fromJsonList(json) AS numbers
+```
+
+**Output:**
+```
+numbers
+-----------
+[1, 2, 3, 4, 5]
+```
+
+### Example 2: Parsing Complex Arrays
+```cypher
+WITH '[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}]' AS json
+WITH flex.json.fromJsonList(json) AS users
+UNWIND users AS user
+RETURN user.id, user.name
+```
+
+### Example 3: Processing Stored List Data
+```cypher
+MATCH (p:Product)
+WHERE p.tagsJson IS NOT NULL
+WITH p, flex.json.fromJsonList(p.tagsJson) AS tags
+UNWIND tags AS tag
+RETURN p.name, tag
+```
+
+### Example 4: Handling Malformed JSON
+```cypher
+WITH '[invalid, json]' AS badJson
+RETURN flex.json.fromJsonList(badJson) AS result
+```
+
+**Output:**
+```
+result
+------
+[]
+```
+(Returns empty list for invalid JSON)
+
+## Notes
+- Returns empty list `[]` if input is not valid JSON
+- Returns empty list if the JSON represents a non-array value (e.g., object, string)
+- Safe to use without error handling as it won't throw exceptions
+- Useful for parsing list data, batch imports, or stored JSON arrays
+
+## See Also
+- [json.fromJsonMap](./fromJsonMap.md) - Parse JSON string to map
+- [json.toJson](./toJson.md) - Serialize value to JSON string
\ No newline at end of file
diff --git a/udfs/flex/json/fromJsonMap.md b/udfs/flex/json/fromJsonMap.md
new file mode 100644
index 00000000..b3e2af53
--- /dev/null
+++ b/udfs/flex/json/fromJsonMap.md
@@ -0,0 +1,81 @@
+---
+layout: default
+title: json.fromJsonMap
+parent: JSON Functions
+grand_parent: FLEX Function Reference
+---
+
+# json.fromJsonMap
+
+## Description
+Parses a JSON string and returns it as a map (object). Safely handles malformed JSON by returning an empty map on parse errors.
+
+## Syntax
+```cypher
+flex.json.fromJsonMap(jsonString)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `jsonString` | string | Yes | A JSON string representing an object |
+
+## Returns
+**Type:** map (object)
+
+A map parsed from the JSON string. Returns an empty map `{}` if parsing fails or if the input is not a valid JSON object.
+
+## Examples
+
+### Example 1: Basic JSON Parsing
+```cypher
+WITH '{"name":"Alice","age":30,"active":true}' AS json
+RETURN flex.json.fromJsonMap(json) AS user
+```
+
+**Output:**
+```
+user
+-------------------------------
+{name: 'Alice', age: 30, active: true}
+```
+
+### Example 2: Parsing Stored JSON Properties
+```cypher
+MATCH (n:Node)
+WHERE n.jsonData IS NOT NULL
+WITH n, flex.json.fromJsonMap(n.jsonData) AS parsed
+RETURN n.id, parsed.field1, parsed.field2
+```
+
+### Example 3: Processing API Responses
+```cypher
+WITH '{"id":123,"email":"user@example.com","role":"admin"}' AS apiResponse
+WITH flex.json.fromJsonMap(apiResponse) AS data
+CREATE (u:User {id: data.id, email: data.email, role: data.role})
+```
+
+### Example 4: Handling Malformed JSON
+```cypher
+WITH '{invalid json}' AS badJson
+RETURN flex.json.fromJsonMap(badJson) AS result
+```
+
+**Output:**
+```
+result
+------
+{}
+```
+(Returns empty map for invalid JSON)
+
+## Notes
+- Returns empty map `{}` if input is not valid JSON
+- Returns empty map if the JSON represents a non-object value (e.g., array, string)
+- Safe to use without error handling as it won't throw exceptions
+- Useful for parsing configuration, API responses, or stored JSON data
+
+## See Also
+- [json.fromJsonList](./fromJsonList.md) - Parse JSON string to list
+- [json.toJson](./toJson.md) - Serialize value to JSON string
\ No newline at end of file
diff --git a/udfs/flex/json/index.md b/udfs/flex/json/index.md
new file mode 100644
index 00000000..d3e22faf
--- /dev/null
+++ b/udfs/flex/json/index.md
@@ -0,0 +1,12 @@
+---
+layout: default
+title: JSON Functions
+parent: FLEX Function Reference
+grand_parent: UDFs
+has_children: true
+nav_order: 40
+---
+
+# JSON Functions
+
+FLEX json utilities.
\ No newline at end of file
diff --git a/udfs/flex/json/toJson.md b/udfs/flex/json/toJson.md
new file mode 100644
index 00000000..aaa71360
--- /dev/null
+++ b/udfs/flex/json/toJson.md
@@ -0,0 +1,80 @@
+---
+layout: default
+title: json.toJson
+parent: JSON Functions
+grand_parent: FLEX Function Reference
+---
+
+# json.toJson
+
+## Description
+Serializes a value to a JSON string. Handles various data types including objects, arrays, strings, numbers, booleans, and `null`.
+
+## Syntax
+```cypher
+flex.json.toJson(value)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `value` | any | Yes | The value to serialize to JSON |
+
+## Returns
+**Type:** string
+
+A JSON string representation of the value. Returns `null` if serialization fails or if the input is `undefined`.
+
+## Examples
+
+### Example 1: Serialize a Map
+```cypher
+WITH {name: 'Alice', age: 30, active: true} AS user
+RETURN flex.json.toJson(user) AS json
+```
+
+**Output:**
+```
+json
+---------------------------------------
+'{"name":"Alice","age":30,"active":true}'
+```
+
+### Example 2: Serialize a List
+```cypher
+WITH [1, 2, 3, 4, 5] AS numbers
+RETURN flex.json.toJson(numbers) AS json
+```
+
+**Output:**
+```
+json
+-----------
+'[1,2,3,4,5]'
+```
+
+### Example 3: Preparing Data for Export
+```cypher
+MATCH (p:Product)
+WITH collect({id: p.id, name: p.name, price: p.price}) AS products
+RETURN flex.json.toJson(products) AS jsonExport
+```
+
+### Example 4: Storing JSON in Properties
+```cypher
+MATCH (u:User {id: 123})
+WITH u, {lastLogin: u.lastLogin, preferences: u.preferences} AS metadata
+SET u.metadataJson = flex.json.toJson(metadata)
+```
+
+## Notes
+- Returns `null` if serialization fails (e.g., circular references)
+- `undefined` values are normalized to `null`
+- Dates are serialized in ISO format
+- Functions and symbols cannot be serialized and will cause `null` return
+- Useful for API responses, data export, or storing complex structures
+
+## See Also
+- [json.fromJsonMap](./fromJsonMap.md) - Parse JSON string to map
+- [json.fromJsonList](./fromJsonList.md) - Parse JSON string to list
\ No newline at end of file
diff --git a/udfs/flex/map/fromPairs.md b/udfs/flex/map/fromPairs.md
new file mode 100644
index 00000000..823a741e
--- /dev/null
+++ b/udfs/flex/map/fromPairs.md
@@ -0,0 +1,83 @@
+---
+layout: default
+title: map.fromPairs
+parent: Map Functions
+grand_parent: FLEX Function Reference
+---
+
+# map.fromPairs
+
+## Description
+Converts a list of key-value pairs into a map. Each pair should be a two-element array `[key, value]`.
+
+## Syntax
+```cypher
+flex.map.fromPairs(pairs)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `pairs` | list | Yes | A list of two-element arrays, each containing `[key, value]` |
+
+## Returns
+**Type:** map (object)
+
+A map where each key-value pair from the input list becomes a property. Returns an empty map if input is not an array.
+
+## Examples
+
+### Example 1: Basic Conversion
+```cypher
+WITH [['name', 'Alice'], ['age', 30], ['city', 'NYC']] AS pairs
+RETURN flex.map.fromPairs(pairs) AS result
+```
+
+**Output:**
+```
+result
+------------------------------------
+{name: 'Alice', age: 30, city: 'NYC'}
+```
+
+### Example 2: Converting Zipped Data
+```cypher
+WITH ['name', 'age', 'email'] AS keys,
+ ['Bob', 25, 'bob@example.com'] AS values
+WITH flex.coll.zip(keys, values) AS pairs
+RETURN flex.map.fromPairs(pairs) AS user
+```
+
+**Output:**
+```
+user
+------------------------------------------
+{name: 'Bob', age: 25, email: 'bob@example.com'}
+```
+
+### Example 3: Dynamic Property Creation
+```cypher
+MATCH (p:Product)
+WITH collect([p.id, p.price]) AS pricePairs
+RETURN flex.map.fromPairs(pricePairs) AS priceMap
+```
+
+### Example 4: Converting Query Results to Lookup Map
+```cypher
+MATCH (c:Country)
+WITH collect([c.code, c.name]) AS countryPairs
+WITH flex.map.fromPairs(countryPairs) AS lookup
+RETURN lookup['US'] AS usaName, lookup['UK'] AS ukName
+```
+
+## Notes
+- Returns empty map if input is not an array or is `null`
+- Each pair must be a two-element array; invalid pairs are skipped
+- If a key is `null` or `undefined`, the pair is ignored
+- Duplicate keys result in the last value being used
+- Keys are converted to strings as map property names
+
+## See Also
+- [coll.zip](../collections/zip.md) - Create pairs from two lists
+- [map.submap](./submap.md) - Extract subset of keys from a map
\ No newline at end of file
diff --git a/udfs/flex/map/index.md b/udfs/flex/map/index.md
new file mode 100644
index 00000000..6a5710cf
--- /dev/null
+++ b/udfs/flex/map/index.md
@@ -0,0 +1,12 @@
+---
+layout: default
+title: Map Functions
+parent: FLEX Function Reference
+grand_parent: UDFs
+has_children: true
+nav_order: 50
+---
+
+# Map Functions
+
+FLEX map utilities.
\ No newline at end of file
diff --git a/udfs/flex/map/merge.md b/udfs/flex/map/merge.md
new file mode 100644
index 00000000..6d2cb928
--- /dev/null
+++ b/udfs/flex/map/merge.md
@@ -0,0 +1,83 @@
+---
+layout: default
+title: map.merge
+parent: Map Functions
+grand_parent: FLEX Function Reference
+---
+
+# map.merge
+
+## Description
+Performs a shallow merge of multiple maps into a new map. When keys conflict, values from later maps override earlier ones. Non-object inputs are ignored.
+
+## Syntax
+```cypher
+flex.map.merge(map1, map2, ...)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `map1` | map | No | First map to merge |
+| `map2` | map | No | Second map to merge |
+| `...` | map | No | Additional maps to merge |
+
+## Returns
+**Type:** map (object)
+
+A new map containing all keys and values from the input maps. Later maps override earlier ones for duplicate keys.
+
+## Examples
+
+### Example 1: Basic Merge
+```cypher
+WITH {a: 1, b: 2} AS map1, {b: 3, c: 4} AS map2
+RETURN flex.map.merge(map1, map2) AS result
+```
+
+**Output:**
+```
+result
+------------------
+{a: 1, b: 3, c: 4}
+```
+(Note: `b` from map2 overrides `b` from map1)
+
+### Example 2: Merging Node Properties
+```cypher
+MATCH (u:User {id: 123})
+WITH {role: 'admin', status: 'active'} AS defaults
+RETURN flex.map.merge(defaults, properties(u)) AS userWithDefaults
+```
+
+### Example 3: Combining Configuration
+```cypher
+WITH {host: 'localhost', port: 6379} AS defaults,
+ {port: 7000, password: 'secret'} AS config
+RETURN flex.map.merge(defaults, config) AS finalConfig
+```
+
+**Output:**
+```
+finalConfig
+--------------------------------------------------
+{host: 'localhost', port: 7000, password: 'secret'}
+```
+
+### Example 4: Merging Multiple Maps
+```cypher
+WITH {a: 1} AS base, {b: 2} AS extra1, {c: 3} AS extra2
+RETURN flex.map.merge(base, extra1, extra2) AS combined
+```
+
+## Notes
+- Non-object inputs are silently ignored
+- Performs shallow merge (nested objects are not deeply merged)
+- Later maps take precedence for duplicate keys
+- Returns a new map; does not modify input maps
+- Useful for applying defaults, combining configuration, or merging properties
+
+## See Also
+- [map.submap](./submap.md) - Extract specific keys from a map
+- [map.removeKeys](./removeKeys.md) - Remove keys from a map
\ No newline at end of file
diff --git a/udfs/flex/map/removeKey.md b/udfs/flex/map/removeKey.md
new file mode 100644
index 00000000..41359fd0
--- /dev/null
+++ b/udfs/flex/map/removeKey.md
@@ -0,0 +1,84 @@
+---
+layout: default
+title: map.removeKey
+parent: Map Functions
+grand_parent: FLEX Function Reference
+---
+
+# map.removeKey
+
+## Description
+Creates a new map with a single specified key removed. The original map is not modified.
+
+## Syntax
+```cypher
+flex.map.removeKey(map, key)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `map` | map | Yes | The map to remove the key from |
+| `key` | string | Yes | The key to remove |
+
+## Returns
+**Type:** map (object)
+
+A new map containing all properties from the input map except the specified key. Returns an empty map if input is not a valid object.
+
+## Examples
+
+### Example 1: Basic Key Removal
+```cypher
+WITH {name: 'Alice', age: 30, email: 'alice@example.com'} AS user
+RETURN flex.map.removeKey(user, 'email') AS sanitized
+```
+
+**Output:**
+```
+sanitized
+-----------------------
+{name: 'Alice', age: 30}
+```
+
+### Example 2: Removing Sensitive Data
+```cypher
+MATCH (u:User)
+WITH properties(u) AS userProps
+RETURN u.id, flex.map.removeKey(userProps, 'password') AS safeProps
+```
+
+### Example 3: Cleaning Response Data
+```cypher
+MATCH (p:Product {id: 123})
+WITH properties(p) AS props
+WITH flex.map.removeKey(props, 'internalId') AS cleaned
+RETURN cleaned AS product
+```
+
+### Example 4: Removing Non-Existent Key
+```cypher
+WITH {a: 1, b: 2} AS map
+RETURN flex.map.removeKey(map, 'c') AS result
+```
+
+**Output:**
+```
+result
+---------
+{a: 1, b: 2}
+```
+(Key doesn't exist, so map is returned unchanged)
+
+## Notes
+- Returns empty map if input is not a valid object or is `null`
+- If key is `null`, returns a shallow copy of the map
+- If the key doesn't exist, returns a copy with all original properties
+- Creates a new map; does not modify the original
+- Useful for sanitizing data, removing sensitive fields, or filtering properties
+
+## See Also
+- [map.removeKeys](./removeKeys.md) - Remove multiple keys at once
+- [map.submap](./submap.md) - Keep only specific keys (inverse operation)
+- [map.merge](./merge.md) - Combine multiple maps
\ No newline at end of file
diff --git a/udfs/flex/map/removeKeys.md b/udfs/flex/map/removeKeys.md
new file mode 100644
index 00000000..51999d77
--- /dev/null
+++ b/udfs/flex/map/removeKeys.md
@@ -0,0 +1,85 @@
+---
+layout: default
+title: map.removeKeys
+parent: Map Functions
+grand_parent: FLEX Function Reference
+---
+
+# map.removeKeys
+
+## Description
+Creates a new map with multiple specified keys removed. The original map is not modified.
+
+## Syntax
+```cypher
+flex.map.removeKeys(map, keys)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `map` | map | Yes | The map to remove keys from |
+| `keys` | list | Yes | An array of key names to remove |
+
+## Returns
+**Type:** map (object)
+
+A new map containing all properties from the input map except the specified keys. Returns an empty map if input is not a valid object.
+
+## Examples
+
+### Example 1: Basic Multiple Key Removal
+```cypher
+WITH {name: 'Alice', age: 30, email: 'alice@example.com', password: 'secret'} AS user
+RETURN flex.map.removeKeys(user, ['password', 'email']) AS sanitized
+```
+
+**Output:**
+```
+sanitized
+-----------------------
+{name: 'Alice', age: 30}
+```
+
+### Example 2: Removing Internal Fields
+```cypher
+MATCH (p:Product)
+WITH properties(p) AS props
+RETURN flex.map.removeKeys(props, ['internalId', 'createdBy', 'updatedAt']) AS public
+```
+
+### Example 3: Filtering Node Properties for API Response
+```cypher
+MATCH (u:User {id: $userId})
+WITH properties(u) AS allProps
+WITH flex.map.removeKeys(allProps, ['password', 'salt', 'resetToken']) AS safeProps
+RETURN safeProps AS user
+```
+
+### Example 4: Removing Non-Existent Keys
+```cypher
+WITH {a: 1, b: 2, c: 3} AS map
+RETURN flex.map.removeKeys(map, ['d', 'e']) AS result
+```
+
+**Output:**
+```
+result
+-----------------
+{a: 1, b: 2, c: 3}
+```
+(Non-existent keys are ignored)
+
+## Notes
+- Returns empty map if input is not a valid object or is `null`
+- `null` values in the keys array are ignored
+- Keys that don't exist in the map are silently ignored
+- Creates a new map; does not modify the original
+- More efficient than calling `removeKey` multiple times
+- Useful for bulk removal of sensitive or internal fields
+
+## See Also
+- [map.removeKey](./removeKey.md) - Remove a single key
+- [map.submap](./submap.md) - Keep only specific keys (inverse operation)
+- [map.merge](./merge.md) - Combine multiple maps
\ No newline at end of file
diff --git a/udfs/flex/map/submap.md b/udfs/flex/map/submap.md
new file mode 100644
index 00000000..ec3b2479
--- /dev/null
+++ b/udfs/flex/map/submap.md
@@ -0,0 +1,90 @@
+---
+layout: default
+title: map.submap
+parent: Map Functions
+grand_parent: FLEX Function Reference
+---
+
+# map.submap
+
+## Description
+Creates a new map containing only the specified keys from the input map. This is the inverse of `removeKeys`.
+
+## Syntax
+```cypher
+flex.map.submap(map, keys)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `map` | map | Yes | The source map to extract keys from |
+| `keys` | list | Yes | An array of key names to include in the result |
+
+## Returns
+**Type:** map (object)
+
+A new map containing only the specified keys and their values from the input map. Returns an empty map if input is not a valid object or keys is not an array.
+
+## Examples
+
+### Example 1: Basic Submap Extraction
+```cypher
+WITH {name: 'Alice', age: 30, email: 'alice@example.com', city: 'NYC'} AS user
+RETURN flex.map.submap(user, ['name', 'email']) AS contact
+```
+
+**Output:**
+```
+contact
+---------------------------------
+{name: 'Alice', email: 'alice@example.com'}
+```
+
+### Example 2: Selecting Specific Node Properties
+```cypher
+MATCH (p:Product)
+RETURN flex.map.submap(properties(p), ['id', 'name', 'price']) AS summary
+```
+
+### Example 3: Building API Response with Selected Fields
+```cypher
+MATCH (u:User {id: $userId})
+WITH properties(u) AS allProps
+RETURN flex.map.submap(allProps, ['id', 'name', 'email', 'role']) AS userInfo
+```
+
+### Example 4: Handling Non-Existent Keys
+```cypher
+WITH {a: 1, b: 2} AS map
+RETURN flex.map.submap(map, ['a', 'c', 'd']) AS result
+```
+
+**Output:**
+```
+result
+------
+{a: 1}
+```
+(Only existing keys are included)
+
+### Example 5: Dynamic Field Selection
+```cypher
+WITH ['name', 'price', 'category'] AS requestedFields
+MATCH (p:Product {id: 123})
+RETURN flex.map.submap(properties(p), requestedFields) AS response
+```
+
+## Notes
+- Returns empty map if input is not a valid object or keys is not an array
+- `null` values in the keys array are ignored
+- Non-existent keys are silently skipped
+- Creates a new map; does not modify the original
+- Useful for selecting specific fields, building API responses, or data projection
+- More efficient than manually picking each field
+
+## See Also
+- [map.removeKeys](./removeKeys.md) - Remove specific keys (inverse operation)
+- [map.removeKey](./removeKey.md) - Remove a single key
+- [map.merge](./merge.md) - Combine multiple maps
\ No newline at end of file
diff --git a/udfs/flex/similarity/index.md b/udfs/flex/similarity/index.md
new file mode 100644
index 00000000..6c816bac
--- /dev/null
+++ b/udfs/flex/similarity/index.md
@@ -0,0 +1,12 @@
+---
+layout: default
+title: Similarity Functions
+parent: FLEX Function Reference
+grand_parent: UDFs
+has_children: true
+nav_order: 60
+---
+
+# Similarity Functions
+
+FLEX similarity utilities.
\ No newline at end of file
diff --git a/udfs/flex/similarity/jaccard.md b/udfs/flex/similarity/jaccard.md
new file mode 100644
index 00000000..4e950fc1
--- /dev/null
+++ b/udfs/flex/similarity/jaccard.md
@@ -0,0 +1,84 @@
+---
+layout: default
+title: sim.jaccard
+parent: Similarity Functions
+grand_parent: FLEX Function Reference
+---
+
+# sim.jaccard
+
+## Description
+Computes the Jaccard similarity coefficient between two sets (lists). The Jaccard index measures the similarity between two sets by dividing the size of their intersection by the size of their union. It returns a value between 0 (no similarity) and 1 (identical sets).
+
+## Syntax
+```cypher
+flex.sim.jaccard(list1, list2)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `list1` | list | Yes | The first list to compare |
+| `list2` | list | Yes | The second list to compare |
+
+## Returns
+**Type:** number (float)
+
+A value between 0 and 1 representing the Jaccard similarity coefficient:
+- `1.0` indicates identical sets
+- `0.0` indicates no common elements
+- Returns `null` for invalid inputs
+
+## Examples
+
+### Example 1: Basic Set Similarity
+```cypher
+// Compare two tag lists
+RETURN flex.sim.jaccard(['tag1', 'tag2', 'tag3'], ['tag2', 'tag3', 'tag4']) AS similarity
+```
+
+**Output:**
+```
+similarity
+----------
+0.5
+```
+(2 common elements / 4 total unique elements = 0.5)
+
+### Example 2: Finding Similar Documents by Tags
+```cypher
+// Find documents with similar tags to a reference document
+MATCH (ref:Document {id: 'doc123'})
+MATCH (other:Document)
+WHERE other.id <> ref.id
+WITH ref, other, flex.sim.jaccard(ref.tags, other.tags) AS similarity
+WHERE similarity > 0.3
+RETURN other.title, similarity
+ORDER BY similarity DESC
+LIMIT 10
+```
+
+### Example 3: User Interest Matching
+```cypher
+// Find users with similar interests
+MATCH (u1:User {id: $userId})
+MATCH (u2:User)
+WHERE u1 <> u2
+WITH u1, u2, flex.sim.jaccard(u1.interests, u2.interests) AS match_score
+WHERE match_score > 0.5
+RETURN u2.name, u2.interests, match_score
+ORDER BY match_score DESC
+```
+
+## Notes
+- Treats input lists as sets (duplicates within each list don't affect the result)
+- Returns `null` if either input is not an array
+- Order of elements doesn't matter
+- Works with any comparable data types (strings, numbers, etc.)
+- Ideal for comparing categorical attributes, tags, or interest lists
+
+## See Also
+- [text.levenshtein](../text/levenshtein.md) - Edit distance for string comparison
+- [coll.intersection](../collections/intersection.md) - Get common elements between sets
+- [coll.union](../collections/union.md) - Combine sets
\ No newline at end of file
diff --git a/udfs/flex/text/camelCase.md b/udfs/flex/text/camelCase.md
new file mode 100644
index 00000000..348ae347
--- /dev/null
+++ b/udfs/flex/text/camelCase.md
@@ -0,0 +1,72 @@
+---
+layout: default
+title: text.camelCase
+parent: Text Functions
+grand_parent: FLEX Function Reference
+---
+
+# text.camelCase
+
+## Description
+Converts a string to camelCase format by removing non-alphanumeric characters and capitalizing the first letter of each word except the first.
+
+## Syntax
+```cypher
+flex.text.camelCase(string)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | string | Yes | The string to convert to camelCase |
+
+## Returns
+**Type:** string
+
+The input string converted to camelCase format. Returns `null` if input is `null`.
+
+## Examples
+
+### Example 1: Basic Usage
+```cypher
+RETURN flex.text.camelCase('hello world') AS result
+```
+
+**Output:**
+```
+result
+----------
+helloWorld
+```
+
+### Example 2: Converting Field Names
+```cypher
+RETURN flex.text.camelCase('user_first_name') AS result
+```
+
+**Output:**
+```
+result
+-------------
+userFirstName
+```
+
+### Example 3: Normalizing Property Names
+```cypher
+WITH ['first-name', 'last_name', 'Email Address'] AS fields
+UNWIND fields AS field
+RETURN field AS original, flex.text.camelCase(field) AS camelCase
+```
+
+## Notes
+- Returns `null` for `null` input
+- Removes all non-alphanumeric characters
+- First character is always lowercase
+- Subsequent words start with uppercase
+- Useful for normalizing field names to JavaScript/JSON conventions
+
+## See Also
+- [text.upperCamelCase](./upperCamelCase.md) - Convert to UpperCamelCase (PascalCase)
+- [text.snakeCase](./snakeCase.md) - Convert to snake_case format
+- [text.capitalize](./capitalize.md) - Capitalize first character only
\ No newline at end of file
diff --git a/udfs/flex/text/capitalize.md b/udfs/flex/text/capitalize.md
new file mode 100644
index 00000000..be4ab8be
--- /dev/null
+++ b/udfs/flex/text/capitalize.md
@@ -0,0 +1,58 @@
+---
+layout: default
+title: text.capitalize
+parent: Text Functions
+grand_parent: FLEX Function Reference
+---
+
+# text.capitalize
+
+## Description
+Capitalizes the first character of a string, converting it to uppercase while leaving the rest of the string unchanged.
+
+## Syntax
+```cypher
+flex.text.capitalize(string)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | string | Yes | The string to capitalize |
+
+## Returns
+**Type:** string
+
+The input string with its first character converted to uppercase. Returns `null` if the input is `null`, and empty string if input is empty.
+
+## Examples
+
+### Example 1: Basic Usage
+```cypher
+RETURN flex.text.capitalize('hello world') AS result
+```
+
+**Output:**
+```
+result
+-------------
+Hello world
+```
+
+### Example 2: Capitalizing Node Properties
+```cypher
+MATCH (p:Person)
+RETURN p.id, flex.text.capitalize(p.name) AS capitalizedName
+```
+
+## Notes
+- Returns `null` for `null` input
+- Returns empty string for empty string input
+- Only affects the first character
+- Does not change the case of subsequent characters
+
+## See Also
+- [text.decapitalize](./decapitalize.md) - Lowercase the first character
+- [text.camelCase](./camelCase.md) - Convert to camelCase format
+- [text.upperCamelCase](./upperCamelCase.md) - Convert to UpperCamelCase format
\ No newline at end of file
diff --git a/udfs/flex/text/decapitalize.md b/udfs/flex/text/decapitalize.md
new file mode 100644
index 00000000..7515b60e
--- /dev/null
+++ b/udfs/flex/text/decapitalize.md
@@ -0,0 +1,58 @@
+---
+layout: default
+title: text.decapitalize
+parent: Text Functions
+grand_parent: FLEX Function Reference
+---
+
+# text.decapitalize
+
+## Description
+Converts the first character of a string to lowercase while leaving the rest of the string unchanged.
+
+## Syntax
+```cypher
+flex.text.decapitalize(string)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | string | Yes | The string to decapitalize |
+
+## Returns
+**Type:** string
+
+The input string with its first character converted to lowercase. Returns `null` if the input is `null`, and empty string if input is empty.
+
+## Examples
+
+### Example 1: Basic Usage
+```cypher
+RETURN flex.text.decapitalize('Hello World') AS result
+```
+
+**Output:**
+```
+result
+-------------
+hello World
+```
+
+### Example 2: Processing Field Names
+```cypher
+WITH ['FirstName', 'LastName', 'Email'] AS fields
+UNWIND fields AS field
+RETURN flex.text.decapitalize(field) AS jsonKey
+```
+
+## Notes
+- Returns `null` for `null` input
+- Returns empty string for empty string input
+- Only affects the first character
+- Does not change the case of subsequent characters
+
+## See Also
+- [text.capitalize](./capitalize.md) - Uppercase the first character
+- [text.camelCase](./camelCase.md) - Convert to camelCase format
\ No newline at end of file
diff --git a/udfs/flex/text/format.md b/udfs/flex/text/format.md
new file mode 100644
index 00000000..4608745a
--- /dev/null
+++ b/udfs/flex/text/format.md
@@ -0,0 +1,73 @@
+---
+layout: default
+title: text.format
+parent: Text Functions
+grand_parent: FLEX Function Reference
+---
+
+# text.format
+
+## Description
+Formats a string by replacing numbered placeholders `{0}`, `{1}`, `{2}`, etc. with corresponding values from a parameters array. Similar to sprintf-style formatting.
+
+## Syntax
+```cypher
+flex.text.format(template, parameters)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `template` | string | Yes | The format string containing `{0}`, `{1}`, etc. placeholders |
+| `parameters` | list | Yes | Array of values to substitute into the template |
+
+## Returns
+**Type:** string
+
+The formatted string with placeholders replaced by parameter values. Returns `null` if template is `null`.
+
+## Examples
+
+### Example 1: Basic String Formatting
+```cypher
+RETURN flex.text.format('Hello {0}, you are {1} years old!', ['Alice', 30]) AS result
+```
+
+**Output:**
+```
+result
+--------------------------------
+Hello Alice, you are 30 years old!
+```
+
+### Example 2: Dynamic Query Messages
+```cypher
+MATCH (u:User {id: 123})
+WITH u, flex.text.format('User {0} ({1}) logged in at {2}', [u.name, u.email, u.lastLogin]) AS message
+RETURN message
+```
+
+### Example 3: Building URLs or Paths
+```cypher
+WITH ['users', 'profile', '12345'] AS parts
+RETURN flex.text.format('/{0}/{1}/{2}', parts) AS path
+```
+
+**Output:**
+```
+path
+------------------------
+/users/profile/12345
+```
+
+## Notes
+- Returns `null` if template is `null`
+- Placeholders are zero-indexed: `{0}`, `{1}`, `{2}`, etc.
+- Same placeholder can be used multiple times in template
+- Parameters are replaced in order of array index
+- Useful for building dynamic messages, logs, or formatted output
+
+## See Also
+- [text.replace](./replace.md) - Replace text using regex patterns
+- [text.join](./join.md) - Join array elements with delimiter
\ No newline at end of file
diff --git a/udfs/flex/text/index.md b/udfs/flex/text/index.md
new file mode 100644
index 00000000..187bff8d
--- /dev/null
+++ b/udfs/flex/text/index.md
@@ -0,0 +1,12 @@
+---
+layout: default
+title: Text Functions
+parent: FLEX Function Reference
+grand_parent: UDFs
+has_children: true
+nav_order: 70
+---
+
+# Text Functions
+
+FLEX text utilities.
\ No newline at end of file
diff --git a/udfs/flex/text/indexOf.md b/udfs/flex/text/indexOf.md
new file mode 100644
index 00000000..cf84e553
--- /dev/null
+++ b/udfs/flex/text/indexOf.md
@@ -0,0 +1,75 @@
+---
+layout: default
+title: text.indexOf
+parent: Text Functions
+grand_parent: FLEX Function Reference
+---
+
+# text.indexOf
+
+## Description
+Finds the first occurrence of a substring within a string, optionally starting from a specific offset and ending at a specific position.
+
+## Syntax
+```cypher
+flex.text.indexOf(string, substring, offset, to)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | string | Yes | The string to search in |
+| `substring` | string | Yes | The substring to search for |
+| `offset` | number | No | Starting position for search (default: 0) |
+| `to` | number | No | Ending position for search (default: -1, meaning end of string) |
+
+## Returns
+**Type:** number (integer)
+
+The zero-based index of the first occurrence of the substring, or `-1` if not found. Returns `null` if the input string is `null`.
+
+## Examples
+
+### Example 1: Basic Search
+```cypher
+RETURN flex.text.indexOf('hello world', 'world') AS position
+```
+
+**Output:**
+```
+position
+--------
+6
+```
+
+### Example 2: Search with Offset
+```cypher
+RETURN flex.text.indexOf('hello hello', 'hello', 3) AS position
+```
+
+**Output:**
+```
+position
+--------
+6
+```
+(Finds the second "hello" starting from position 3)
+
+### Example 3: Filtering Nodes by Substring Position
+```cypher
+MATCH (p:Product)
+WHERE flex.text.indexOf(p.description, 'premium') >= 0
+RETURN p.name, p.description
+```
+
+## Notes
+- Returns `null` if input string is `null`
+- Returns `-1` if substring is not found
+- Uses zero-based indexing
+- The `offset` parameter allows starting search from a specific position
+- The `to` parameter limits search to a specific range
+
+## See Also
+- [text.indexesOf](./indexesOf.md) - Find all occurrences of a substring
+- [text.replace](./replace.md) - Replace substring occurrences
\ No newline at end of file
diff --git a/udfs/flex/text/indexesOf.md b/udfs/flex/text/indexesOf.md
new file mode 100644
index 00000000..a213f96c
--- /dev/null
+++ b/udfs/flex/text/indexesOf.md
@@ -0,0 +1,79 @@
+---
+layout: default
+title: text.indexesOf
+parent: Text Functions
+grand_parent: FLEX Function Reference
+---
+
+# text.indexesOf
+
+## Description
+Finds all occurrences of a substring within a string, returning an array of all matching positions. Optionally search within a specific range.
+
+## Syntax
+```cypher
+flex.text.indexesOf(string, substring, from, to)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | string | Yes | The string to search in |
+| `substring` | string | Yes | The substring to search for |
+| `from` | number | No | Starting position for search (default: 0) |
+| `to` | number | No | Ending position for search (default: -1, meaning end of string) |
+
+## Returns
+**Type:** list of numbers
+
+An array containing the zero-based indices of all occurrences of the substring. Returns an empty array if no matches are found. Returns `null` if the input string is `null`.
+
+## Examples
+
+### Example 1: Find All Occurrences
+```cypher
+RETURN flex.text.indexesOf('hello hello hello', 'hello') AS positions
+```
+
+**Output:**
+```
+positions
+-----------
+[0, 6, 12]
+```
+
+### Example 2: Find Occurrences in Range
+```cypher
+RETURN flex.text.indexesOf('abcabcabc', 'abc', 1, 9) AS positions
+```
+
+**Output:**
+```
+positions
+---------
+[3, 6]
+```
+(Skips first 'abc' at position 0, finds those within range)
+
+### Example 3: Count Keyword Occurrences
+```cypher
+MATCH (d:Document)
+WITH d, flex.text.indexesOf(d.content, 'important') AS occurrences
+WHERE size(occurrences) > 2
+RETURN d.title, size(occurrences) AS importanceScore
+ORDER BY importanceScore DESC
+```
+
+## Notes
+- Returns `null` if input string is `null`
+- Returns empty array if substring is not found
+- Uses zero-based indexing
+- The `from` parameter allows starting search from a specific position
+- The `to` parameter limits search to a specific range
+- Useful for counting occurrences or analyzing text patterns
+
+## See Also
+- [text.indexOf](./indexOf.md) - Find first occurrence only
+- [text.replace](./replace.md) - Replace substring occurrences
+- [text.regexGroups](./regexGroups.md) - Find matches using regex patterns
\ No newline at end of file
diff --git a/udfs/flex/text/jaroWinkler.md b/udfs/flex/text/jaroWinkler.md
new file mode 100644
index 00000000..0e25ef29
--- /dev/null
+++ b/udfs/flex/text/jaroWinkler.md
@@ -0,0 +1,79 @@
+---
+layout: default
+title: text.jaroWinkler
+parent: Text Functions
+grand_parent: FLEX Function Reference
+---
+
+# text.jaroWinkler
+
+## Description
+Computes the Jaro-Winkler similarity between two strings. This metric is particularly effective for short strings like names and addresses. It gives more favorable ratings to strings that match from the beginning. Returns a value between 0 (no similarity) and 1 (exact match).
+
+## Syntax
+```cypher
+flex.text.jaroWinkler(string1, string2)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string1` | string | Yes | The first string to compare |
+| `string2` | string | Yes | The second string to compare |
+
+## Returns
+**Type:** number (float)
+
+A similarity score between 0 and 1:
+- `1.0` indicates an exact match
+- `0.0` indicates no similarity
+- Higher values indicate greater similarity
+
+## Examples
+
+### Example 1: Name Matching
+```cypher
+// Compare similar names
+RETURN flex.text.jaroWinkler('Martha', 'Marhta') AS similarity
+```
+
+**Output:**
+```
+similarity
+----------
+0.961
+```
+
+### Example 2: Fuzzy Name Search
+```cypher
+// Find people with names similar to "William"
+MATCH (p:Person)
+WHERE flex.text.jaroWinkler(p.firstName, 'William') > 0.85
+RETURN p.firstName, p.lastName, flex.text.jaroWinkler(p.firstName, 'William') AS score
+ORDER BY score DESC
+```
+
+### Example 3: Deduplication by Company Name
+```cypher
+// Find potential duplicate company records
+MATCH (c1:Company)
+MATCH (c2:Company)
+WHERE id(c1) < id(c2)
+WITH c1, c2, flex.text.jaroWinkler(c1.name, c2.name) AS similarity
+WHERE similarity > 0.9
+RETURN c1.name, c2.name, similarity
+ORDER BY similarity DESC
+```
+
+## Notes
+- Particularly effective for short strings (names, addresses)
+- Gives higher weight to strings that match from the beginning
+- Handles `null` values by returning appropriate default values
+- Case-sensitive comparison
+- More forgiving than exact match but stricter than pure Jaro similarity
+- Commonly used in record linkage and deduplication tasks
+
+## See Also
+- [text.levenshtein](./levenshtein.md) - Edit distance metric for string comparison
+- [sim.jaccard](../similarity/jaccard.md) - Set-based similarity
\ No newline at end of file
diff --git a/udfs/flex/text/join.md b/udfs/flex/text/join.md
new file mode 100644
index 00000000..955c4cdd
--- /dev/null
+++ b/udfs/flex/text/join.md
@@ -0,0 +1,85 @@
+---
+layout: default
+title: text.join
+parent: Text Functions
+grand_parent: FLEX Function Reference
+---
+
+# text.join
+
+## Description
+Joins an array of strings into a single string using a specified delimiter.
+
+## Syntax
+```cypher
+flex.text.join(array, delimiter)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `array` | list | Yes | The array of strings to join |
+| `delimiter` | string | Yes | The separator to insert between elements |
+
+## Returns
+**Type:** string
+
+A single string with all array elements concatenated, separated by the delimiter. Returns `null` if the array is `null` or undefined.
+
+## Examples
+
+### Example 1: Basic String Joining
+```cypher
+RETURN flex.text.join(['apple', 'banana', 'cherry'], ', ') AS result
+```
+
+**Output:**
+```
+result
+----------------------
+apple, banana, cherry
+```
+
+### Example 2: Building CSV Lines
+```cypher
+MATCH (u:User)
+WITH [u.id, u.name, u.email] AS fields
+RETURN flex.text.join(fields, ',') AS csvLine
+```
+
+### Example 3: Creating Tags String
+```cypher
+MATCH (p:Post)
+RETURN p.title, flex.text.join(p.tags, ' #') AS hashtags
+```
+
+**Output:**
+```
+title | hashtags
+----------------|------------------
+My First Post | tech #coding #js
+```
+
+### Example 4: Building Paths
+```cypher
+WITH ['home', 'user', 'documents', 'file.txt'] AS parts
+RETURN flex.text.join(parts, '/') AS path
+```
+
+**Output:**
+```
+path
+--------------------------
+home/user/documents/file.txt
+```
+
+## Notes
+- Returns `null` if input array is `null`
+- Empty strings in the array are included in the output
+- Delimiter can be any string, including empty string
+- Commonly used for CSV generation, path building, or tag formatting
+
+## See Also
+- [text.format](./format.md) - Format strings with placeholders
+- [coll.zip](../collections/zip.md) - Combine two lists
\ No newline at end of file
diff --git a/udfs/flex/text/levenshtein.md b/udfs/flex/text/levenshtein.md
new file mode 100644
index 00000000..b80b2d6b
--- /dev/null
+++ b/udfs/flex/text/levenshtein.md
@@ -0,0 +1,76 @@
+---
+layout: default
+title: text.levenshtein
+parent: Text Functions
+grand_parent: FLEX Function Reference
+---
+
+# text.levenshtein
+
+## Description
+Computes the Levenshtein edit distance between two strings. The edit distance is the minimum number of single-character edits (insertions, deletions, or substitutions) required to change one string into another. This is useful for fuzzy string matching, spell checking, and finding similar records.
+
+## Syntax
+```cypher
+flex.text.levenshtein(string1, string2)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string1` | string | Yes | The first string to compare |
+| `string2` | string | Yes | The second string to compare |
+
+## Returns
+**Type:** number (integer)
+
+The minimum number of single-character edits needed to transform `string1` into `string2`. Returns `0` if the strings are identical.
+
+## Examples
+
+### Example 1: Basic String Comparison
+```cypher
+// Compare two similar strings
+RETURN flex.text.levenshtein('kitten', 'sitting') AS distance
+```
+
+**Output:**
+```
+distance
+--------
+3
+```
+
+### Example 2: Finding Similar User Names
+```cypher
+// Find users with names similar to "Sarah" within edit distance of 2
+MATCH (u:User)
+WHERE flex.text.levenshtein(u.name, 'Sarah') <= 2
+RETURN u.name, u.email, flex.text.levenshtein(u.name, 'Sarah') AS distance
+ORDER BY distance
+```
+
+### Example 3: Fuzzy Matching with Multiple Candidates
+```cypher
+// Find the closest matching product name
+WITH 'iPhone' AS search_term
+MATCH (p:Product)
+WITH p, flex.text.levenshtein(p.name, search_term) AS distance
+WHERE distance <= 3
+RETURN p.name, distance
+ORDER BY distance
+LIMIT 5
+```
+
+## Notes
+- Handles `null` values gracefully by treating them as empty strings
+- The function is symmetric: `levenshtein(a, b) = levenshtein(b, a)`
+- Empty strings return the length of the non-empty string as distance
+- Two `null` values return distance of `0`
+- Optimized for performance with memory-efficient implementation
+- Case-sensitive comparison (use `toLower()` if case-insensitive matching is needed)
+
+## See Also
+- [sim.jaccard](../similarity/jaccard.md) - Set-based similarity for collections
+- [text.jaroWinkler](./jaroWinkler.md) - Alternative string similarity metric
\ No newline at end of file
diff --git a/udfs/flex/text/lpad.md b/udfs/flex/text/lpad.md
new file mode 100644
index 00000000..d02344f6
--- /dev/null
+++ b/udfs/flex/text/lpad.md
@@ -0,0 +1,85 @@
+---
+layout: default
+title: text.lpad
+parent: Text Functions
+grand_parent: FLEX Function Reference
+---
+
+# text.lpad
+
+## Description
+Pads the start (left side) of a string with a specified character until it reaches the desired length.
+
+## Syntax
+```cypher
+flex.text.lpad(string, length, padChar)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | string/number | Yes | The string to pad (will be converted to string if number) |
+| `length` | number | Yes | The target length after padding |
+| `padChar` | string | No | The character to use for padding (default: space ' ') |
+
+## Returns
+**Type:** string
+
+The padded string. If the original string is already longer than the target length, it is returned unchanged. Returns `null` if input is `null`.
+
+## Examples
+
+### Example 1: Basic Left Padding
+```cypher
+RETURN flex.text.lpad('5', 3, '0') AS result
+```
+
+**Output:**
+```
+result
+------
+005
+```
+
+### Example 2: Formatting Numbers with Leading Zeros
+```cypher
+MATCH (o:Order)
+RETURN flex.text.lpad(toString(o.id), 8, '0') AS orderId
+```
+
+**Output:**
+```
+orderId
+--------
+00000123
+00000456
+```
+
+### Example 3: Aligning Text
+```cypher
+WITH ['Total:', 'Subtotal:', 'Tax:'] AS labels
+UNWIND labels AS label
+RETURN flex.text.lpad(label, 12, ' ') AS aligned
+```
+
+**Output:**
+```
+aligned
+--------------
+ Total:
+ Subtotal:
+ Tax:
+```
+
+## Notes
+- Returns `null` if input is `null`
+- Converts numbers to strings automatically
+- Default padding character is a space
+- If string is already longer than target length, returns original string
+- Useful for formatting IDs, aligning columns, or creating fixed-width output
+
+## See Also
+- [text.rpad](./rpad.md) - Pad the end (right side) of a string
+- [text.repeat](./repeat.md) - Repeat a string multiple times
+- [text.format](./format.md) - Format strings with placeholders
\ No newline at end of file
diff --git a/udfs/flex/text/regexGroups.md b/udfs/flex/text/regexGroups.md
new file mode 100644
index 00000000..f0380eee
--- /dev/null
+++ b/udfs/flex/text/regexGroups.md
@@ -0,0 +1,78 @@
+---
+layout: default
+title: text.regexGroups
+parent: Text Functions
+grand_parent: FLEX Function Reference
+---
+
+# text.regexGroups
+
+## Description
+Extracts all matches and capture groups from a string using a regular expression pattern. Returns a nested array where each match contains the full match and any captured groups.
+
+## Syntax
+```cypher
+flex.text.regexGroups(string, regex)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | string | Yes | The string to search in |
+| `regex` | string | Yes | The regular expression pattern (applied globally) |
+
+## Returns
+**Type:** list of lists
+
+A nested array where each inner array represents one match and contains the full match followed by any capture groups. Returns `null` if input string is `null`.
+
+## Examples
+
+### Example 1: Extract Email Components
+```cypher
+WITH 'Contact: john@example.com or jane@test.org' AS text
+RETURN flex.text.regexGroups(text, '(\\w+)@(\\w+\\.\\w+)') AS matches
+```
+
+**Output:**
+```
+matches
+----------------------------------------------------
+[["john@example.com", "john", "example.com"],
+ ["jane@test.org", "jane", "test.org"]]
+```
+
+### Example 2: Parse Date Components
+```cypher
+WITH '2024-01-15 and 2024-12-25' AS dates
+RETURN flex.text.regexGroups(dates, '(\\d{4})-(\\d{2})-(\\d{2})') AS parsed
+```
+
+**Output:**
+```
+parsed
+-------------------------------------------------
+[["2024-01-15", "2024", "01", "15"],
+ ["2024-12-25", "2024", "12", "25"]]
+```
+
+### Example 3: Extract URLs and Protocol
+```cypher
+MATCH (d:Document)
+WITH d, flex.text.regexGroups(d.content, '(https?)://([\\w.]+)') AS urls
+WHERE size(urls) > 0
+RETURN d.title, urls
+```
+
+## Notes
+- Returns `null` if input string is `null`
+- The regex is applied globally (finds all matches)
+- Each match array contains: [fullMatch, group1, group2, ...]
+- Useful for parsing structured text, extracting data patterns
+- More powerful than simple string search for complex patterns
+
+## See Also
+- [text.replace](./replace.md) - Replace text using regex
+- [text.indexOf](./indexOf.md) - Find simple substring position
+- [text.indexesOf](./indexesOf.md) - Find all substring positions
\ No newline at end of file
diff --git a/udfs/flex/text/repeat.md b/udfs/flex/text/repeat.md
new file mode 100644
index 00000000..d4eeafa4
--- /dev/null
+++ b/udfs/flex/text/repeat.md
@@ -0,0 +1,93 @@
+---
+layout: default
+title: text.repeat
+parent: Text Functions
+grand_parent: FLEX Function Reference
+---
+
+# text.repeat
+
+## Description
+Repeats a string a specified number of times.
+
+## Syntax
+```cypher
+flex.text.repeat(string, count)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | string | Yes | The string to repeat |
+| `count` | number | Yes | The number of times to repeat the string |
+
+## Returns
+**Type:** string
+
+A new string consisting of the input string repeated the specified number of times. Returns `null` if input is `null`.
+
+## Examples
+
+### Example 1: Basic Repetition
+```cypher
+RETURN flex.text.repeat('Ha', 3) AS result
+```
+
+**Output:**
+```
+result
+------
+HaHaHa
+```
+
+### Example 2: Creating Separators
+```cypher
+RETURN flex.text.repeat('-', 40) AS separator
+```
+
+**Output:**
+```
+separator
+----------------------------------------
+----------------------------------------
+```
+
+### Example 3: Building Star Ratings
+```cypher
+MATCH (r:Review)
+RETURN r.product, flex.text.repeat('β
', r.rating) AS stars
+```
+
+**Output:**
+```
+product | stars
+------------|-------
+Laptop | β
β
β
β
β
+Mouse | β
β
β
β
+Keyboard | β
β
β
+```
+
+### Example 4: Indentation
+```cypher
+WITH 2 AS level
+RETURN flex.text.repeat(' ', level) + 'Nested Item' AS indented
+```
+
+**Output:**
+```
+indented
+----------------
+ Nested Item
+```
+
+## Notes
+- Returns `null` if input is `null`
+- Count must be a non-negative integer
+- Useful for creating visual elements, separators, or formatting
+- Can be combined with other text functions for complex formatting
+
+## See Also
+- [text.lpad](./lpad.md) - Pad the start of a string
+- [text.rpad](./rpad.md) - Pad the end of a string
+- [text.format](./format.md) - Format strings with placeholders
\ No newline at end of file
diff --git a/udfs/flex/text/replace.md b/udfs/flex/text/replace.md
new file mode 100644
index 00000000..f6cbba61
--- /dev/null
+++ b/udfs/flex/text/replace.md
@@ -0,0 +1,88 @@
+---
+layout: default
+title: text.replace
+parent: Text Functions
+grand_parent: FLEX Function Reference
+---
+
+# text.replace
+
+## Description
+Replaces all occurrences of a substring matching a regular expression pattern with a replacement string.
+
+## Syntax
+```cypher
+flex.text.replace(string, regex, replacement)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | string | Yes | The string to perform replacements on |
+| `regex` | string | Yes | The regular expression pattern to match (applied globally) |
+| `replacement` | string | Yes | The string to replace matches with |
+
+## Returns
+**Type:** string
+
+A new string with all pattern matches replaced by the replacement string. Returns `null` if input string is `null`.
+
+## Examples
+
+### Example 1: Basic Text Replacement
+```cypher
+RETURN flex.text.replace('hello world', 'world', 'universe') AS result
+```
+
+**Output:**
+```
+result
+--------------
+hello universe
+```
+
+### Example 2: Remove Non-Numeric Characters
+```cypher
+WITH 'Phone: (555) 123-4567' AS phone
+RETURN flex.text.replace(phone, '[^0-9]', '') AS cleaned
+```
+
+**Output:**
+```
+cleaned
+-----------
+5551234567
+```
+
+### Example 3: Sanitize User Input
+```cypher
+MATCH (c:Comment)
+WITH c, flex.text.replace(c.text, '<[^>]+>', '') AS sanitized
+RETURN sanitized AS cleanComment
+```
+
+### Example 4: Normalize Whitespace
+```cypher
+WITH ' Multiple spaces here ' AS text
+RETURN flex.text.replace(text, '\\s+', ' ') AS normalized
+```
+
+**Output:**
+```
+normalized
+-------------------------
+ Multiple spaces here
+```
+
+## Notes
+- Returns `null` if input string is `null`
+- Uses global replacement (replaces all occurrences)
+- Pattern is treated as a regular expression
+- Useful for data cleaning, sanitization, and text transformation
+- Can use regex patterns for complex replacements
+
+## See Also
+- [text.regexGroups](./regexGroups.md) - Extract matches with capture groups
+- [text.indexOf](./indexOf.md) - Find substring position
+- [text.format](./format.md) - Format strings with placeholders
\ No newline at end of file
diff --git a/udfs/flex/text/rpad.md b/udfs/flex/text/rpad.md
new file mode 100644
index 00000000..fa6f3b13
--- /dev/null
+++ b/udfs/flex/text/rpad.md
@@ -0,0 +1,76 @@
+---
+layout: default
+title: text.rpad
+parent: Text Functions
+grand_parent: FLEX Function Reference
+---
+
+# text.rpad
+
+## Description
+Pads the end (right side) of a string with a specified character until it reaches the desired length.
+
+## Syntax
+```cypher
+flex.text.rpad(string, length, padChar)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | string/number | Yes | The string to pad (will be converted to string if number) |
+| `length` | number | Yes | The target length after padding |
+| `padChar` | string | No | The character to use for padding (default: space ' ') |
+
+## Returns
+**Type:** string
+
+The padded string. If the original string is already longer than the target length, it is returned unchanged. Returns `null` if input is `null`.
+
+## Examples
+
+### Example 1: Basic Right Padding
+```cypher
+RETURN flex.text.rpad('test', 8, '-') AS result
+```
+
+**Output:**
+```
+result
+----------
+test----
+```
+
+### Example 2: Creating Fixed-Width Fields
+```cypher
+MATCH (p:Product)
+RETURN flex.text.rpad(p.name, 20, ' ') AS productName, p.price
+```
+
+**Output:**
+```
+productName | price
+---------------------|-------
+Laptop | 999.99
+Mouse | 29.99
+```
+
+### Example 3: Building Formatted Tables
+```cypher
+WITH [['Name', 15], ['Email', 25], ['Role', 10]] AS columns
+UNWIND columns AS col
+RETURN flex.text.rpad(col[0], col[1], ' ') AS header
+```
+
+## Notes
+- Returns `null` if input is `null`
+- Converts numbers to strings automatically
+- Default padding character is a space
+- If string is already longer than target length, returns original string
+- Useful for creating aligned columns, fixed-width output, or formatted tables
+
+## See Also
+- [text.lpad](./lpad.md) - Pad the start (left side) of a string
+- [text.repeat](./repeat.md) - Repeat a string multiple times
+- [text.format](./format.md) - Format strings with placeholders
\ No newline at end of file
diff --git a/udfs/flex/text/snakeCase.md b/udfs/flex/text/snakeCase.md
new file mode 100644
index 00000000..3da5377b
--- /dev/null
+++ b/udfs/flex/text/snakeCase.md
@@ -0,0 +1,78 @@
+---
+layout: default
+title: text.snakeCase
+parent: Text Functions
+grand_parent: FLEX Function Reference
+---
+
+# text.snakeCase
+
+## Description
+Converts a string to snake_case format by separating words with underscores and converting all characters to lowercase.
+
+## Syntax
+```cypher
+flex.text.snakeCase(string)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | string | Yes | The string to convert to snake_case |
+
+## Returns
+**Type:** string
+
+The input string converted to snake_case format. Returns the original string if no matches are found. Returns `null` if input is `null`.
+
+## Examples
+
+### Example 1: Basic Usage
+```cypher
+RETURN flex.text.snakeCase('HelloWorld') AS result
+```
+
+**Output:**
+```
+result
+-----------
+hello_world
+```
+
+### Example 2: Converting Multiple Formats
+```cypher
+WITH ['camelCase', 'PascalCase', 'kebab-case', 'space separated'] AS inputs
+UNWIND inputs AS input
+RETURN input AS original, flex.text.snakeCase(input) AS snake
+```
+
+**Output:**
+```
+original | snake
+----------------|------------------
+camelCase | camel_case
+PascalCase | pascal_case
+kebab-case | kebab_case
+space separated | space_separated
+```
+
+### Example 3: Database Column Naming
+```cypher
+MATCH (u:User)
+WITH u, keys(u) AS properties
+UNWIND properties AS prop
+RETURN prop AS camelCase, flex.text.snakeCase(prop) AS dbColumn
+```
+
+## Notes
+- Returns `null` for `null` input
+- Handles multiple word boundary detection patterns
+- All characters are converted to lowercase
+- Words are separated by underscores
+- Common for database column names and Python conventions
+- Returns the original string if no word boundaries are detected
+
+## See Also
+- [text.camelCase](./camelCase.md) - Convert to camelCase format
+- [text.upperCamelCase](./upperCamelCase.md) - Convert to UpperCamelCase format
\ No newline at end of file
diff --git a/udfs/flex/text/swapCase.md b/udfs/flex/text/swapCase.md
new file mode 100644
index 00000000..88d176e7
--- /dev/null
+++ b/udfs/flex/text/swapCase.md
@@ -0,0 +1,63 @@
+---
+layout: default
+title: text.swapCase
+parent: Text Functions
+grand_parent: FLEX Function Reference
+---
+
+# text.swapCase
+
+## Description
+Swaps the case of each character in a string - uppercase characters become lowercase and vice versa.
+
+## Syntax
+```cypher
+flex.text.swapCase(string)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | string | Yes | The string to swap case |
+
+## Returns
+**Type:** string
+
+A new string with all uppercase characters converted to lowercase and all lowercase characters converted to uppercase. Returns `null` if input is `null`.
+
+## Examples
+
+### Example 1: Basic Usage
+```cypher
+RETURN flex.text.swapCase('Hello World') AS result
+```
+
+**Output:**
+```
+result
+-------------
+hELLO wORLD
+```
+
+### Example 2: Swapping Mixed Case
+```cypher
+RETURN flex.text.swapCase('aBc123XyZ') AS result
+```
+
+**Output:**
+```
+result
+----------
+AbC123xYz
+```
+
+## Notes
+- Returns `null` for `null` input
+- Non-alphabetic characters remain unchanged
+- Applies to all characters in the string, not just the first
+
+## See Also
+- [text.capitalize](./capitalize.md) - Uppercase the first character
+- [text.camelCase](./camelCase.md) - Convert to camelCase format
+- [text.snakeCase](./snakeCase.md) - Convert to snake_case format
\ No newline at end of file
diff --git a/udfs/flex/text/upperCamelCase.md b/udfs/flex/text/upperCamelCase.md
new file mode 100644
index 00000000..703a74de
--- /dev/null
+++ b/udfs/flex/text/upperCamelCase.md
@@ -0,0 +1,71 @@
+---
+layout: default
+title: text.upperCamelCase
+parent: Text Functions
+grand_parent: FLEX Function Reference
+---
+
+# text.upperCamelCase
+
+## Description
+Converts a string to UpperCamelCase (also known as PascalCase) format by removing non-alphanumeric characters and capitalizing the first letter of each word including the first.
+
+## Syntax
+```cypher
+flex.text.upperCamelCase(string)
+```
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | string | Yes | The string to convert to UpperCamelCase |
+
+## Returns
+**Type:** string
+
+The input string converted to UpperCamelCase format. Returns `null` if input is `null`.
+
+## Examples
+
+### Example 1: Basic Usage
+```cypher
+RETURN flex.text.upperCamelCase('hello world') AS result
+```
+
+**Output:**
+```
+result
+----------
+HelloWorld
+```
+
+### Example 2: Converting Class Names
+```cypher
+RETURN flex.text.upperCamelCase('user_account') AS result
+```
+
+**Output:**
+```
+result
+-----------
+UserAccount
+```
+
+### Example 3: Normalizing Entity Names
+```cypher
+MATCH (e:Entity)
+RETURN e.rawName, flex.text.upperCamelCase(e.rawName) AS className
+```
+
+## Notes
+- Returns `null` for `null` input
+- Removes all non-alphanumeric characters
+- First character is always uppercase (unlike camelCase)
+- Also known as PascalCase
+- Useful for class names, type names, and entity naming conventions
+
+## See Also
+- [text.camelCase](./camelCase.md) - Convert to camelCase (first letter lowercase)
+- [text.snakeCase](./snakeCase.md) - Convert to snake_case format
+- [text.capitalize](./capitalize.md) - Capitalize first character only
\ No newline at end of file
diff --git a/udfs/index.md b/udfs/index.md
new file mode 100644
index 00000000..200bd459
--- /dev/null
+++ b/udfs/index.md
@@ -0,0 +1,422 @@
+---
+layout: default
+title: UDFs
+has_children: true
+nav_order: 6
+---
+
+# UDFs
+
+Every database comes with a set of built-in functions. For example, FalkorDB functions include:
+- `abs` - computes the absolute value of a number
+- `pow` - computes v^x
+- `trim` - removes leading and trailing spaces.
+
+These functions are built into the database and are part of its source code. Introducing a new function (for example, `UpperCaseOdd`) is not always trivial. The function needs to be usable to a wide audience for it to be considered. In the past, FalkorDB has rejected requests for adding new functions when these were too specific and did not add significant value for most users.
+
+However, with the support of UDFs, everyone can extend FalkorDB's functionality with their own set of functions. The following sections introduce UDFs and explain how to manage and use them within FalkorDB.
+
+
+## Practical Example
+To introduce UDFs, review the following complete example, which loads a new UDF library called "StringUtils" that includes a single function called "UpperCaseOdd". Once loaded, the script puts the function to use.
+
+```python
+from falkordb import FalkorDB
+
+# Connect to FalkorDB
+db = FalkorDB(host='localhost', port=6379)
+
+# Define UDF library name & script
+lib = "StringUtils"
+
+# UpperCaseOdd implementation in JavaScript
+script = """
+function UpperCaseOdd(s) {
+ return s.split('')
+ .map((char, i) => {
+ if (i % 2 !== 0) {
+ return char.toUpperCase();
+ }
+ return char;
+ })
+ .join('');
+};
+
+// expose UDF to FalkorDB
+falkor.register('UpperCaseOdd', UpperCaseOdd);
+"""
+
+# Load UDF into the database
+db.udf_load(lib, script)
+
+# Call UDF
+graph = db.select_graph("G")
+s = graph.query("RETURN StringUtils.UpperCaseOdd('abcdef')").result_set[0][0]
+print(f"s: {s}") # prints 'AbCdEf'
+```
+## Commands Specification
+
+The FalkorDB-PY Python client provides convenient access to UDF functionality, but FalkorDB also exposes this functionality via a set of GRAPH.UDF commands.
+
+### GRAPH.UDF LOAD [REPLACE]