> For the complete documentation index, see [llms.txt](https://docs.lingoql.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.lingoql.com/introduction/services-you-can-deploy.md).

# Services you can deploy

LingoQL supports managed data services and app deploys in one platform.

If your app can build with `Railpack` or `Nixpacks`, LingoQL can run it.

### Managed databases and data services

#### SQL and relational

* PostgreSQL
* PgVector
* TimescaleDB
* MySQL
* MariaDB
* LibSQL

#### Document, graph, and wide-column

* MongoDB
* FerretDB
* CouchDB
* Neo4j
* ScyllaDB
* Cassandra

#### Cache, queue, search, and analytics

* Redis
* Valkey
* KeyDB
* Memcached
* RabbitMQ
* ClickHouse
* InfluxDB
* Elasticsearch
* immudb

### Websites, frontends, and backend apps

#### Websites and frontend apps

Deploy static or SSR apps from frameworks such as:

* Next.js, React, Vue, Nuxt, and Svelte
* SolidStart, Qwik, and Flutter Web
* other frontend stacks supported by `Railpack` or `Nixpacks`

LingoQL detects the app type, installs dependencies, builds it, and runs the correct start command.

#### Backend apps and APIs

Deploy backend services built with languages such as:

* Rust, Go, PHP, and Haskell
* Node.js, Python, Java, and Ruby
* other server runtimes supported by `Railpack` or `Nixpacks`

This works for APIs, workers, cron services, and long-running processes.

### Self-hosted tools and packaged apps

LingoQL can also run many packaged services and internal tools.

Common examples include:

* Portainer, pgAdmin, Adminer, DbGate, Grafana, and MinIO
* NocoBase, Odoo, WordPress, Ghost, Drupal, PrestaShop, Joomla, LimeSurvey, and Actual Budget
* Keycloak, Authentik, Hasura, Jenkins, SonarQube, Metabase, Chatwoot, AFFiNE, Activepieces, Healthchecks, Uptime Kuma, Browserless, Docmost, PocketBase, Trilium, Draw\.io, Postiz, Akaunting, Kong, Konga, Flare, Gitness, LLaNA, and VictoriaMetrics

### Common connection rules

LingoQL injects two runtime environment variables into deploys:

* `HOST`
* `PORT`

Use them to bind your server.

If your framework only accepts a port and a literal host, bind to `0.0.0.0` and read `PORT`.

Many managed TCP services on LingoQL also require:

* TLS enabled
* port `443`
* SNI set to the service hostname

{% hint style="info" %}
Replace every sample host, user, password, database name, and token with your own values.
{% endhint %}

### Redis, Valkey, and KeyDB

All Redis-compatible deployments use TLS.

Use a `rediss://` connection string.

Enable TLS in your client.

Set `servername` or the TLS host to your Redis hostname.

Without TLS and SNI, the connection will fail.

### immudb connection example

Use TLS on port `443`.

Log in first.

Then switch to the target database.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/metadata"

    immudb "github.com/codenotary/immudb/pkg/api/schema"
)

func main() {
    creds := credentials.NewTLS(nil)

    conn, err := grpc.Dial(
        "<your-immudb-host>:443",
        grpc.WithTransportCredentials(creds),
        grpc.WithTimeout(30*time.Second),
    )
    if err != nil {
        log.Fatal("connection failed:", err)
    }
    defer conn.Close()

    client := immudb.NewImmuServiceClient(conn)
    ctx := context.Background()

    loginResp, err := client.Login(ctx, &immudb.LoginRequest{
        User:     []byte("immudb"),
        Password: []byte("<your-immudb-password>"),
    })
    if err != nil {
        log.Fatal("login failed:", err)
    }

    authCtx := metadata.NewOutgoingContext(ctx, metadata.Pairs(
        "authorization", loginResp.Token,
    ))

    _, err = client.UseDatabase(authCtx, &immudb.Database{
        DatabaseName: "defaultdb",
    })
    if err != nil {
        log.Fatal("use database failed:", err)
    }

    _, err = client.Set(authCtx, &immudb.SetRequest{
        KVs: []*immudb.KeyValue{{
            Key:   []byte("hello"),
            Value: []byte("world"),
        }},
    })
    if err != nil {
        log.Fatal("set failed:", err)
    }

    res, err := client.Get(authCtx, &immudb.KeyRequest{
        Key: []byte("hello"),
    })
    if err != nil {
        log.Fatal("get failed:", err)
    }

    fmt.Println(string(res.Value))
}
```

### Neo4j HTTP connection example

Use the HTTPS endpoint.

Send requests to `/db/neo4j/tx/commit`.

Pass your Basic auth token in the `Authorization` header.

```rust
use reqwest::Client;
use std::error::Error;

async fn test_neo4j() -> Result<(), Box<dyn Error>> {
    let base_url = "https://<your-neo4j-host>:443";
    let authorization_token = "<your-basic-auth-token>";

    let client = Client::builder().build()?;
    let url = format!("{base_url}/db/neo4j/tx/commit");

    let body = serde_json::json!({
        "statements": [{
            "statement": "RETURN 'Hello Neo4j from Rust!' AS message, datetime() AS timestamp, 1 + 1 AS calculation"
        }]
    });

    let response = client
        .post(&url)
        .header("Authorization", format!("Basic {authorization_token}"))
        .json(&body)
        .send()
        .await?;

    println!("status: {}", response.status());
    println!("body: {}", response.text().await?);

    Ok(())
}
```

### ScyllaDB or Cassandra connection example

Use TLS on port `443`.

Set `ServerName` to the hostname.

Disable initial host lookup for proxy-style routing.

```go
package main

import (
    "crypto/tls"
    "fmt"
    "log"

    "github.com/gocql/gocql"
)

func main() {
    host := "<your-scylladb-host>"
    cluster := gocql.NewCluster(host + ":443")

    cluster.SslOpts = &gocql.SslOptions{
        Config: &tls.Config{
            ServerName: host,
        },
    }

    cluster.Authenticator = &gocql.PasswordAuthenticator{
        Username: "<your-username>",
        Password: "<your-password>",
    }

    cluster.DisableInitialHostLookup = true

    session, err := cluster.CreateSession()
    if err != nil {
        log.Fatal("failed to connect:", err)
    }
    defer session.Close()

    var version string
    if err := session.Query("SELECT release_version FROM system.local").Scan(&version); err != nil {
        log.Fatal("query failed:", err)
    }

    fmt.Println(version)
}
```

### RabbitMQ connection example

Use `amqps://`.

Enable TLS.

Set `ServerName` for SNI.

```go
package main

import (
    "crypto/tls"
    "log"

    amqp "github.com/rabbitmq/amqp091-go"
)

func main() {
    host := "<your-rabbitmq-host>"
    url := "amqps://<user>:<password>@" + host + ":443/<your-vhost>"

    tlsConfig := &tls.Config{
        ServerName: host,
    }

    conn, err := amqp.DialTLS(url, tlsConfig)
    if err != nil {
        log.Fatal("failed to connect:", err)
    }
    defer conn.Close()

    log.Println("connected")
}
```

### ClickHouse connection example

Use TLS on port `443`.

Pass the service hostname as `ServerName`.

```go
package main

import (
    "context"
    "crypto/tls"
    "fmt"
    "log"
    "time"

    "github.com/ClickHouse/clickhouse-go/v2"
)

func main() {
    host := "<your-clickhouse-host>"

    opts := &clickhouse.Options{
        Addr: []string{fmt.Sprintf("%s:%d", host, 443)},
        Auth: clickhouse.Auth{
            Database: "<your-database>",
            Username: "<your-username>",
            Password: "<your-password>",
        },
        TLS: &tls.Config{
            ServerName: host,
        },
        DialTimeout: 60 * time.Second,
        Compression: &clickhouse.Compression{
            Method: clickhouse.CompressionLZ4,
        },
    }

    conn := clickhouse.OpenDB(opts)

    var version string
    if err := conn.QueryRowContext(context.Background(), "SELECT version()").Scan(&version); err != nil {
        log.Fatal("query failed:", err)
    }

    log.Println(version)
}
```

### Memcached connection example

Use a TLS dialer.

Set `ServerName` to the service hostname.

```go
package main

import (
    "context"
    "crypto/tls"
    "fmt"
    "log"
    "net"

    "github.com/bradfitz/gomemcache/memcache"
)

func main() {
    host := "<your-memcached-host>"
    addr := host + ":443"

    client := memcache.New(addr)
    client.DialContext = func(ctx context.Context, network, _ string) (net.Conn, error) {
        return tls.Dial(network, addr, &tls.Config{ServerName: host})
    }

    if err := client.Set(&memcache.Item{
        Key:        "test",
        Value:      []byte("hello"),
        Expiration: 60,
    }); err != nil {
        log.Fatal("set failed:", err)
    }

    item, err := client.Get("test")
    if err != nil {
        log.Fatal("get failed:", err)
    }

    fmt.Println(string(item.Value))
}
```

### Next steps

* Use [Build failures](/introduction/troubleshooting-deploys/build-failures.md) when build detection or native dependencies fail.
* Use [Runtime and startup failures](/introduction/troubleshooting-deploys/runtime-and-startup-failures.md) when the app boots locally but fails on LingoQL.
* Use [Troubleshooting Deploys](/introduction/troubleshooting-deploys.md) for the full deploy recovery flow.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.lingoql.com/introduction/services-you-can-deploy.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
