diff --git a/examples/apollo-tracing.graphql b/examples/apollo-tracing.graphql
deleted file mode 100644
index 368ff53c17..0000000000
--- a/examples/apollo-tracing.graphql
+++ /dev/null
@@ -1,14 +0,0 @@
-schema @server(port: 8000, hostname: "0.0.0.0") @telemetry(export: {apollo: {apiKey: "1234", graphRef: "abc@123"}}) {
-  query: Query
-}
-
-type Query @cache(maxAge: 30000) {
-  posts: [Post] @http(url: "http://jsonplaceholder.typicode.com/posts")
-}
-
-type Post {
-  id: Int!
-  userId: Int!
-  title: String!
-  body: String!
-}
diff --git a/examples/apollo-tracing.yaml b/examples/apollo-tracing.yaml
new file mode 100644
index 0000000000..5b6d82d593
--- /dev/null
+++ b/examples/apollo-tracing.yaml
@@ -0,0 +1,14 @@
+# yaml-language-server: $schema=../generated/.tailcallrc.schema.json
+
+server:
+  port: 8000
+  hostname: "0.0.0.0"
+
+telemetry:
+  export:
+    apollo:
+      apiKey: "1234"
+      graphRef: "abc@123"
+
+links:
+  - src: ./jsonplaceholder.graphql
diff --git a/examples/apollo_federation_subgraph_post.graphql b/examples/apollo_federation_subgraph_post.graphql
index b1e36ab105..840e97f7aa 100644
--- a/examples/apollo_federation_subgraph_post.graphql
+++ b/examples/apollo_federation_subgraph_post.graphql
@@ -1,7 +1,3 @@
-schema @server(port: 8001, enableFederation: true) @upstream(httpCache: 42, batch: {delay: 100}) {
-  query: Query
-}
-
 type Query {
   posts: [Post] @http(url: "http://jsonplaceholder.typicode.com/posts")
 }
diff --git a/examples/apollo_federation_subgraph_post.yaml b/examples/apollo_federation_subgraph_post.yaml
new file mode 100644
index 0000000000..997dd6b4ac
--- /dev/null
+++ b/examples/apollo_federation_subgraph_post.yaml
@@ -0,0 +1,13 @@
+# yaml-language-server: $schema=../generated/.tailcallrc.schema.json
+
+server:
+  port: 8001
+  enableFederation: true
+
+upstream:
+  batch:
+    delay: 100
+  httpCache: 42
+
+links:
+  - src: ./apollo_federation_subgraph_post.graphql
diff --git a/examples/apollo_federation_subgraph_user.graphql b/examples/apollo_federation_subgraph_user.graphql
index 262b96684e..2e8cb17638 100644
--- a/examples/apollo_federation_subgraph_user.graphql
+++ b/examples/apollo_federation_subgraph_user.graphql
@@ -1,7 +1,3 @@
-schema @server(port: 8002, enableFederation: true) @upstream(httpCache: 42, batch: {delay: 100}) {
-  query: Query
-}
-
 type Query {
   user(id: Int!): User @http(url: "http://jsonplaceholder.typicode.com/users/{{.args.id}}")
 }
diff --git a/examples/apollo_federation_subgraph_user.yaml b/examples/apollo_federation_subgraph_user.yaml
new file mode 100644
index 0000000000..868dcbd0cf
--- /dev/null
+++ b/examples/apollo_federation_subgraph_user.yaml
@@ -0,0 +1,13 @@
+# yaml-language-server: $schema=../generated/.tailcallrc.schema.json
+
+server:
+  port: 8002
+  enableFederation: true
+
+upstream:
+  batch:
+    delay: 100
+  httpCache: 42
+
+links:
+  - src: ./apollo_federation_subgraph_user.graphql
diff --git a/examples/auth.graphql b/examples/auth.graphql
index f335e85197..d2dfc8ada8 100644
--- a/examples/auth.graphql
+++ b/examples/auth.graphql
@@ -1,12 +1,3 @@
-schema
-  @server(port: 8000)
-  @upstream(httpCache: 42)
-  @link(id: "auth-basic", type: Htpasswd, src: ".htpasswd")
-  @link(id: "auth-jwt", type: Jwks, src: ".jwks") {
-  query: Query
-  mutation: Mutation
-}
-
 type Query {
   posts: [Post] @http(url: "http://jsonplaceholder.typicode.com/posts")
   user(id: Int!): User @http(url: "http://jsonplaceholder.typicode.com/users/{{.args.id}}")
diff --git a/examples/auth.yaml b/examples/auth.yaml
new file mode 100644
index 0000000000..ce902554c7
--- /dev/null
+++ b/examples/auth.yaml
@@ -0,0 +1,16 @@
+# yaml-language-server: $schema=../generated/.tailcallrc.schema.json
+
+server:
+  port: 8000
+
+upstream:
+  httpCache: 42
+
+links:
+  - src: ./auth.graphql
+  - type: Htpasswd
+    id: auth-basic
+    src: .htpasswd
+  - type: Jwks
+    id: auth-jwt
+    src: .jwks
diff --git a/examples/call.yaml b/examples/call.yaml
new file mode 100644
index 0000000000..61f9913853
--- /dev/null
+++ b/examples/call.yaml
@@ -0,0 +1,4 @@
+# yaml-language-server: $schema=../generated/.tailcallrc.schema.json
+
+links:
+  - src: ./call.graphql
diff --git a/examples/cors.graphql b/examples/cors.graphql
deleted file mode 100644
index 27a4d12674..0000000000
--- a/examples/cors.graphql
+++ /dev/null
@@ -1,19 +0,0 @@
-schema
-  @server(
-    port: 8000
-    hostname: "0.0.0.0"
-    headers: {cors: {allowOrigins: ["*"], allowHeaders: ["*"], allowMethods: [POST, GET, OPTIONS]}}
-  ) {
-  query: Query
-}
-
-type Query {
-  posts: [Post] @http(url: "http://jsonplaceholder.typicode.com/posts")
-}
-
-type Post {
-  id: Int!
-  userId: Int!
-  title: String!
-  body: String!
-}
diff --git a/examples/cors.yaml b/examples/cors.yaml
new file mode 100644
index 0000000000..90b644331c
--- /dev/null
+++ b/examples/cors.yaml
@@ -0,0 +1,18 @@
+# yaml-language-server: $schema=../generated/.tailcallrc.schema.json
+
+server:
+  port: 8000
+  hostname: "0.0.0.0"
+  headers:
+    cors:
+      allowOrigins:
+        - "*"
+      allowHeaders:
+        - "*"
+      allowMethods:
+        - POST
+        - GET
+        - OPTIONS
+
+links:
+  - src: ./jsonplaceholder.graphql
diff --git a/examples/empty-to-jsonplaceholder.graphql b/examples/empty-to-jsonplaceholder.graphql
deleted file mode 100644
index 9025e80964..0000000000
--- a/examples/empty-to-jsonplaceholder.graphql
+++ /dev/null
@@ -1,3 +0,0 @@
-schema @server @upstream @link(type: Config, src: "jsonplaceholder.graphql") {
-  query: Query
-}
diff --git a/examples/graphql-composition.graphql b/examples/graphql-composition.graphql
index b4d5e0c6d1..4643f91f21 100644
--- a/examples/graphql-composition.graphql
+++ b/examples/graphql-composition.graphql
@@ -1,11 +1,7 @@
 # To run this example first start another tailcall server with basic example
-# i.e. `tc start examples/jsonplaceholder.graphql`
+# i.e. `tc start examples/jsonplaceholder.yaml`
 # and then you can run this example and test it on 8001 port
 
-schema @server(port: 8001, queryValidation: false, hostname: "0.0.0.0") @upstream(httpCache: 42, batch: {delay: 1}) {
-  query: Query
-}
-
 type Query {
   posts: [Post] @graphQL(url: "http://jsonplaceholder.typicode.com", name: "posts")
 }
diff --git a/examples/graphql-composition.yaml b/examples/graphql-composition.yaml
new file mode 100644
index 0000000000..d344c6dedd
--- /dev/null
+++ b/examples/graphql-composition.yaml
@@ -0,0 +1,14 @@
+# yaml-language-server: $schema=../generated/.tailcallrc.schema.json
+
+server:
+  port: 8001
+  queryValidation: false
+  hostname: "0.0.0.0"
+
+upstream:
+  httpCache: 42
+  batch:
+    delay: 1
+
+links:
+  - src: ./graphql-composition.graphql
diff --git a/examples/grpc-reflection.graphql b/examples/grpc-reflection.graphql
deleted file mode 100644
index 841350bbe6..0000000000
--- a/examples/grpc-reflection.graphql
+++ /dev/null
@@ -1,42 +0,0 @@
-# for test upstream server see [repo](https://github.com/tailcallhq/tailcall/tree/main/tailcall-upstream-grpc)
-schema
-  @server(port: 8000)
-  @upstream(httpCache: 42, batch: {delay: 10})
-  @link(src: "http://localhost:50051", type: Grpc, headers: [{key: "authorization", value: "Bearer 123"}]) {
-  query: Query
-}
-
-type Query {
-  news: NewsData! @grpc(url: "http://localhost:50051", method: "news.NewsService.GetAllNews")
-  newsById(news: NewsInput!): News!
-    @grpc(url: "http://localhost:50051", method: "news.NewsService.GetNews", body: "{{args.news}}")
-  newsByIdBatch(news: NewsInput!): News!
-    @grpc(
-      url: "http://localhost:50051"
-      method: "news.NewsService.GetMultipleNews"
-      body: "{{args.news}}"
-      batchKey: ["news", "id"]
-    )
-}
-
-type News {
-  id: Int
-  title: String
-  body: String
-  postImage: String
-  status: Status
-}
-
-enum Status {
-  PUBLISHED
-  DRAFT
-  DELETED
-}
-
-input NewsInput {
-  id: Int
-}
-
-type NewsData {
-  news: [News]
-}
diff --git a/examples/grpc-reflection.yaml b/examples/grpc-reflection.yaml
new file mode 100644
index 0000000000..0e5b35a741
--- /dev/null
+++ b/examples/grpc-reflection.yaml
@@ -0,0 +1,19 @@
+# yaml-language-server: $schema=../generated/.tailcallrc.schema.json
+
+server:
+  port: 8000
+
+upstream:
+  httpCache: 42
+  batch:
+    delay:
+      10
+
+links:
+  - src: ./grpc.graphql
+  - type: Grpc
+    # for test upstream server see [repo](https://github.com/tailcallhq/tailcall/tree/main/tailcall-upstream-grpc)
+    src: http://localhost:50051
+    headers:
+      - key: authorization
+        value: Bearer 123
diff --git a/examples/grpc.graphql b/examples/grpc.graphql
index 995cea0043..cd50e4532d 100644
--- a/examples/grpc.graphql
+++ b/examples/grpc.graphql
@@ -1,20 +1,12 @@
-# for test upstream server see [repo](https://github.com/tailcallhq/rust-grpc)
-schema
-  @server(port: 8000)
-  @upstream(httpCache: 42, batch: {delay: 10})
-  @link(id: "news", src: "../tailcall-fixtures/fixtures/protobuf/news.proto", type: Protobuf) {
-  query: Query
-}
-
 type Query {
   news: NewsData! @grpc(url: "http://localhost:50051", method: "news.NewsService.GetAllNews")
   newsById(news: NewsInput!): News!
-    @grpc(url: "http://localhost:50051", method: "news.NewsService.GetNews", body: "{{.args.news}}")
+    @grpc(url: "http://localhost:50051", method: "news.NewsService.GetNews", body: "{{args.news}}")
   newsByIdBatch(news: NewsInput!): News!
     @grpc(
       url: "http://localhost:50051"
       method: "news.NewsService.GetMultipleNews"
-      body: "{{.args.news}}"
+      body: "{{args.news}}"
       batchKey: ["news", "id"]
     )
 }
diff --git a/examples/grpc.yaml b/examples/grpc.yaml
new file mode 100644
index 0000000000..475fd470a6
--- /dev/null
+++ b/examples/grpc.yaml
@@ -0,0 +1,16 @@
+# yaml-language-server: $schema=../generated/.tailcallrc.schema.json
+
+server:
+  port: 8000
+
+upstream:
+  httpCache: 42
+  batch:
+    delay: 10
+
+links:
+  - src: grpc.graphql
+  # for test upstream server see [repo](https://github.com/tailcallhq/rust-grpc)
+  - type: Protobuf
+    id: news
+    src: "../tailcall-fixtures/fixtures/protobuf/news.proto"
diff --git a/examples/jsonplaceholder.graphql b/examples/jsonplaceholder.graphql
index 46aebf0105..380ddd4236 100644
--- a/examples/jsonplaceholder.graphql
+++ b/examples/jsonplaceholder.graphql
@@ -1,7 +1,3 @@
-schema @server(port: 8000) @upstream(httpCache: 42, batch: {delay: 100}) {
-  query: Query
-}
-
 type Query {
   posts: [Post] @http(url: "http://jsonplaceholder.typicode.com/posts")
   users: [User] @http(url: "http://jsonplaceholder.typicode.com/users")
diff --git a/examples/jsonplaceholder.yaml b/examples/jsonplaceholder.yaml
index f1edf73537..6bff86efe5 100644
--- a/examples/jsonplaceholder.yaml
+++ b/examples/jsonplaceholder.yaml
@@ -9,4 +9,4 @@ upstream:
   httpCache: 42
 
 links:
-  - src: ./jsonplaceholder.graphql
+  - src: jsonplaceholder.graphql
diff --git a/examples/jsonplaceholder_batch.graphql b/examples/jsonplaceholder_batch.graphql
index 1722c6d686..239dbe7e9e 100644
--- a/examples/jsonplaceholder_batch.graphql
+++ b/examples/jsonplaceholder_batch.graphql
@@ -1,7 +1,3 @@
-schema @server(port: 8000) @upstream(httpCache: 42, batch: {delay: 1, maxSize: 1000}) {
-  query: Query
-}
-
 type Query {
   posts: [Post] @http(url: "http://jsonplaceholder.typicode.com/posts")
 }
diff --git a/examples/jsonplaceholder_batch.yaml b/examples/jsonplaceholder_batch.yaml
new file mode 100644
index 0000000000..0486db7c85
--- /dev/null
+++ b/examples/jsonplaceholder_batch.yaml
@@ -0,0 +1,13 @@
+# yaml-language-server: $schema=../generated/.tailcallrc.schema.json
+
+server:
+  port: 8000
+
+upstream:
+  batch:
+    delay: 1
+    maxSize: 1000
+  httpCache: 42
+
+links:
+  - src: jsonplaceholder_batch.graphql
diff --git a/examples/jsonplaceholder_http_2.graphql b/examples/jsonplaceholder_http_2.graphql
index 1d6d917e95..e9937d1973 100644
--- a/examples/jsonplaceholder_http_2.graphql
+++ b/examples/jsonplaceholder_http_2.graphql
@@ -1,11 +1,3 @@
-schema
-  @server(port: 3000, queryValidation: false, hostname: "0.0.0.0", version: HTTP2)
-  @link(type: Cert, src: "./example.crt")
-  @link(type: Key, src: "./example.key")
-  @upstream(httpCache: 42) {
-  query: Query
-}
-
 type Query {
   posts: [Post] @http(url: "http://jsonplaceholder.typicode.com/posts")
 }
diff --git a/examples/jsonplaceholder_http_2.yaml b/examples/jsonplaceholder_http_2.yaml
new file mode 100644
index 0000000000..9cda653bc0
--- /dev/null
+++ b/examples/jsonplaceholder_http_2.yaml
@@ -0,0 +1,17 @@
+# yaml-language-server: $schema=../generated/.tailcallrc.schema.json
+
+server:
+  port: 3000
+  queryValidation: false
+  hostname: "0.0.0.0"
+  version: HTTP2
+
+upstream:
+  httpCache: 42
+
+links:
+  - src: ./jsonplaceholder_http_2.graphql
+  - type: Cert
+    src: ./example.crt
+  - type: Key
+    src: ./example.key
diff --git a/examples/jsonplaceholder_script.graphql b/examples/jsonplaceholder_script.graphql
index 1f9fa90553..257f7239a5 100644
--- a/examples/jsonplaceholder_script.graphql
+++ b/examples/jsonplaceholder_script.graphql
@@ -1,10 +1,3 @@
-schema
-  @server(port: 8000, hostname: "0.0.0.0")
-  @upstream(httpCache: 42, onRequest: "onRequest")
-  @link(type: Script, src: "scripts/echo.js") {
-  query: Query
-}
-
 type Query {
   posts: [Post] @http(url: "http://jsonplaceholder.typicode.com/posts", onResponseBody: "onResponse")
   user(id: Int!): User
diff --git a/examples/jsonplaceholder_script.yaml b/examples/jsonplaceholder_script.yaml
new file mode 100644
index 0000000000..d798145a11
--- /dev/null
+++ b/examples/jsonplaceholder_script.yaml
@@ -0,0 +1,13 @@
+# yaml-language-server: $schema=../generated/.tailcallrc.schema.json
+
+server:
+  port: 8000
+  hostname: "0.0.0.0"
+
+upstream:
+  httpCache: 42
+
+links:
+  - src: ./jsonplaceholder_script.graphql
+  - type: Script
+    src: scripts/echo.js
diff --git a/examples/lint.sh b/examples/lint.sh
index 0ff6895547..39a4bcac62 100755
--- a/examples/lint.sh
+++ b/examples/lint.sh
@@ -12,9 +12,11 @@ error_exit() {
 check_files() {
   local path="./examples"
   local depth=1
-  local -a extensions=("-name" "*.json" -o "-name" "*.yml" -o "-name" "*.yaml" -o "-name" "*.graphql" -o "-name" "*.gql")
-  local command="./target/debug/tailcall check"
-  local -a ignore=("!" "-name" "grpc-reflection.graphql" "!" "-name" "generate.yml")
+  local -a extensions=("-name" "*.json" -o "-name" "*.yml" -o "-name" "*.yaml")
+  local command="cargo run -- check"
+  # ignore grpc-reflection because it requires a running grpc server
+  # ignore generate.yaml because it's used for generation and not service commands
+  local -a ignore=("!" "-name" "grpc-reflection.yaml" "!" "-name" "generate.yml")
 
   # Execute find command with constructed options and extensions
   find "$path" -maxdepth "$depth" \( "${extensions[@]}" \) "${ignore[@]}" -exec sh -c '
diff --git a/examples/rest-api.graphql b/examples/rest-api.graphql
index bc9a45aedd..afec7d5aa3 100644
--- a/examples/rest-api.graphql
+++ b/examples/rest-api.graphql
@@ -1,10 +1,3 @@
-schema
-  @server(port: 8000, hostname: "0.0.0.0")
-  @upstream(httpCache: 42)
-  @link(type: Operation, src: "operations/routes.graphql") {
-  query: Query
-}
-
 type Query {
   posts: [Post] @http(url: "http://jsonplaceholder.typicode.com/posts")
   users: [User] @http(url: "http://jsonplaceholder.typicode.com/users")
diff --git a/examples/rest-api.yaml b/examples/rest-api.yaml
new file mode 100644
index 0000000000..a333000460
--- /dev/null
+++ b/examples/rest-api.yaml
@@ -0,0 +1,13 @@
+# yaml-language-server: $schema=../generated/.tailcallrc.schema.json
+
+server:
+  port: 8000
+  hostname: "0.0.0.0"
+
+upstream:
+  httpCache: 42
+
+links:
+  - src: ./rest-api.graphql
+  - type: Operation
+    src: operations/routes.graphql
diff --git a/examples/telemetry-otlp.yaml b/examples/telemetry-otlp.yaml
new file mode 100644
index 0000000000..11e50a6c09
--- /dev/null
+++ b/examples/telemetry-otlp.yaml
@@ -0,0 +1,26 @@
+# yaml-language-server: $schema=../generated/.tailcallrc.schema.json
+
+server:
+  port: 8000
+  hostname: "0.0.0.0"
+
+upstream:
+  httpCache: 42
+
+links:
+  - src: ./telemetry.graphql
+  - type: Operation
+    src: operations/routes.graphql
+  - type: Protobuf
+    id: news
+    src: "../tailcall-fixtures/fixtures/protobuf/news.proto"
+
+telemetry:
+  export:
+    otlp:
+      url: "https://api.honeycomb.io:443"
+      headers:
+        - key: x-honeycomb-team
+          value: "{{.env.HONEYCOMB_API_KEY}}"
+        - key: x-honeycomb-dataset
+          value: tailcall
diff --git a/examples/telemetry-prometheus.graphql b/examples/telemetry-prometheus.graphql
deleted file mode 100644
index aecb4660f2..0000000000
--- a/examples/telemetry-prometheus.graphql
+++ /dev/null
@@ -1,28 +0,0 @@
-schema
-  @server(port: 8000, hostname: "0.0.0.0")
-  @upstream(httpCache: 42)
-  @telemetry(export: {prometheus: {path: "/metrics"}}) {
-  query: Query
-}
-
-type Query {
-  posts: [Post] @http(url: "http://jsonplaceholder.typicode.com/posts") @cache(maxAge: 5000)
-  user(id: Int!): User @http(url: "http://jsonplaceholder.typicode.com/users/{{.args.id}}")
-}
-
-type User {
-  id: Int!
-  name: String!
-  username: String!
-  email: String!
-  phone: String
-  website: String
-}
-
-type Post {
-  id: Int!
-  userId: Int!
-  title: String!
-  body: String!
-  user: User @http(url: "http://jsonplaceholder.typicode.com/users/{{.value.userId}}")
-}
diff --git a/examples/telemetry-prometheus.yaml b/examples/telemetry-prometheus.yaml
new file mode 100644
index 0000000000..4cae6f964c
--- /dev/null
+++ b/examples/telemetry-prometheus.yaml
@@ -0,0 +1,21 @@
+# yaml-language-server: $schema=../generated/.tailcallrc.schema.json
+
+server:
+  port: 8000
+  hostname: "0.0.0.0"
+
+upstream:
+  httpCache: 42
+
+links:
+  - src: ./telemetry.graphql
+  - type: Operation
+    src: operations/routes.graphql
+  - type: Protobuf
+    id: news
+    src: "../tailcall-fixtures/fixtures/protobuf/news.proto"
+
+telemetry:
+  export:
+    prometheus:
+      path: /metrics
diff --git a/examples/telemetry-stdout.graphql b/examples/telemetry-stdout.graphql
deleted file mode 100644
index 70eac8f7bb..0000000000
--- a/examples/telemetry-stdout.graphql
+++ /dev/null
@@ -1,25 +0,0 @@
-schema @server(port: 8000, hostname: "0.0.0.0") @upstream(httpCache: 42) @telemetry(export: {stdout: {pretty: true}}) {
-  query: Query
-}
-
-type Query {
-  posts: [Post] @http(url: "http://jsonplaceholder.typicode.com/posts") @cache(maxAge: 5000)
-  user(id: Int!): User @http(url: "http://jsonplaceholder.typicode.com/users/{{.args.id}}")
-}
-
-type User {
-  id: Int!
-  name: String!
-  username: String!
-  email: String!
-  phone: String
-  website: String
-}
-
-type Post {
-  id: Int!
-  userId: Int!
-  title: String!
-  body: String!
-  user: User @http(url: "http://jsonplaceholder.typicode.com/users/{{.value.userId}}")
-}
diff --git a/examples/telemetry-stdout.yaml b/examples/telemetry-stdout.yaml
new file mode 100644
index 0000000000..1dcb69a922
--- /dev/null
+++ b/examples/telemetry-stdout.yaml
@@ -0,0 +1,21 @@
+# yaml-language-server: $schema=../generated/.tailcallrc.schema.json
+
+server:
+  port: 8000
+  hostname: "0.0.0.0"
+
+upstream:
+  httpCache: 42
+
+links:
+  - src: ./telemetry.graphql
+  - type: Operation
+    src: operations/routes.graphql
+  - type: Protobuf
+    id: news
+    src: "../tailcall-fixtures/fixtures/protobuf/news.proto"
+
+telemetry:
+  export:
+    stdout:
+      pretty: true
diff --git a/examples/telemetry-otlp.graphql b/examples/telemetry.graphql
similarity index 55%
rename from examples/telemetry-otlp.graphql
rename to examples/telemetry.graphql
index 35001b9252..65a3bbd752 100644
--- a/examples/telemetry-otlp.graphql
+++ b/examples/telemetry.graphql
@@ -1,24 +1,3 @@
-schema
-  @server(port: 8000, hostname: "0.0.0.0")
-  @upstream(httpCache: 42)
-  @link(type: Operation, src: "operations/routes.graphql")
-  @link(id: "news", src: "../tailcall-fixtures/fixtures/protobuf/news.proto", type: Protobuf)
-  @telemetry(
-    export: {
-      otlp: {
-        url: "https://api.honeycomb.io:443"
-        # gather api key from https://ui.honeycomb.io and set it as env when running tailcall
-        headers: [
-          {key: "x-honeycomb-team", value: "{{.env.HONEYCOMB_API_KEY}}"}
-          {key: "x-honeycomb-dataset", value: "tailcall"}
-        ]
-      }
-    }
-    requestHeaders: ["user-id"]
-  ) {
-  query: Query
-}
-
 type Query {
   posts: [Post] @http(url: "http://jsonplaceholder.typicode.com/posts") @cache(maxAge: 3000)
   user(id: Int!): User @http(url: "http://jsonplaceholder.typicode.com/users/{{.args.id}}")
diff --git a/src/core/blueprint/error.rs b/src/core/blueprint/error.rs
index 4d4dd6337b..ff7601ba28 100644
--- a/src/core/blueprint/error.rs
+++ b/src/core/blueprint/error.rs
@@ -136,9 +136,6 @@ pub enum BlueprintError {
     #[error("unknown template directive '{0}'")]
     UnknownTemplateDirective(String),
 
-    #[error("Query root is missing")]
-    QueryRootIsMissing,
-
     #[error("Query type is not defined")]
     QueryTypeNotDefined,
 
diff --git a/src/core/blueprint/schema.rs b/src/core/blueprint/schema.rs
index 3acf956a9b..c194e67d10 100644
--- a/src/core/blueprint/schema.rs
+++ b/src/core/blueprint/schema.rs
@@ -7,19 +7,24 @@ use crate::core::blueprint::*;
 use crate::core::config::{Config, Field, Type};
 use crate::core::directive::DirectiveCodec;
 
-fn validate_query(config: &Config) -> Valid<(), BlueprintError> {
-    Valid::from_option(
-        config.schema.query.clone(),
-        BlueprintError::QueryRootIsMissing,
-    )
-    .and_then(|ref query_type_name| {
-        let Some(query) = config.find_type(query_type_name) else {
-            return Valid::fail(BlueprintError::QueryTypeNotDefined).trace(query_type_name);
-        };
-        let mut set = HashSet::new();
-        validate_type_has_resolvers(query_type_name, query, &config.types, &mut set)
-    })
-    .unit()
+fn validate_query(config: &Config) -> Valid<&str, BlueprintError> {
+    let query_type_name = config
+        .schema
+        .query
+        .as_deref()
+        // Based on the [spec](https://spec.graphql.org/October2021/#sec-Root-Operation-Types.Default-Root-Operation-Type-Names)
+        // the default name for query type is `Query` is not specified explicitly
+        .unwrap_or("Query");
+
+    let Some(query) = config.find_type(query_type_name) else {
+        // from spec: The query root operation type must be provided and must be an
+        // Object type.
+        return Valid::fail(BlueprintError::QueryTypeNotDefined).trace(query_type_name);
+    };
+    let mut set = HashSet::new();
+
+    validate_type_has_resolvers(query_type_name, query, &config.types, &mut set)
+        .map_to(query_type_name)
 }
 
 /// Validates that all the root type fields has resolver
@@ -65,33 +70,40 @@ pub fn validate_field_has_resolver(
         .trace(name)
 }
 
-fn validate_mutation(config: &Config) -> Valid<(), BlueprintError> {
-    let mutation_type_name = config.schema.mutation.as_ref();
+fn validate_mutation(config: &Config) -> Valid<Option<&str>, BlueprintError> {
+    let mutation_type_name = config
+        .schema
+        .mutation
+        .as_deref()
+        // Based on the [spec](https://spec.graphql.org/October2021/#sec-Root-Operation-Types.Default-Root-Operation-Type-Names)
+        // the default name for mutation type is `Mutation` is not specified explicitly
+        .unwrap_or("Mutation");
 
-    if let Some(mutation_type_name) = mutation_type_name {
-        let Some(mutation) = config.find_type(mutation_type_name) else {
-            return Valid::fail(BlueprintError::MutationTypeNotDefined).trace(mutation_type_name);
-        };
+    if let Some(mutation) = config.find_type(mutation_type_name) {
         let mut set = HashSet::new();
         validate_type_has_resolvers(mutation_type_name, mutation, &config.types, &mut set)
+            .map_to(Some(mutation_type_name))
+    } else if config.schema.mutation.is_some() {
+        // if mutation was specified by schema but not found raise the error
+        Valid::fail(BlueprintError::MutationTypeNotDefined).trace(mutation_type_name)
     } else {
-        Valid::succeed(())
+        // otherwise if mutation is not specified and default type is not found just
+        // return None
+        Valid::succeed(None)
     }
 }
 
 pub fn to_schema<'a>() -> TryFoldConfig<'a, SchemaDefinition> {
     TryFoldConfig::new(|config, _| {
         validate_query(config)
-            .and(validate_mutation(config))
-            .and(Valid::from_option(
-                config.schema.query.as_ref(),
-                BlueprintError::QueryRootIsMissing,
-            ))
-            .zip(to_directive(config.server.to_directive()))
-            .map(|(query_type_name, directive)| SchemaDefinition {
-                query: query_type_name.to_owned(),
-                mutation: config.schema.mutation.clone(),
-                directives: vec![directive],
-            })
+            .fuse(validate_mutation(config))
+            .fuse(to_directive(config.server.to_directive()))
+            .map(
+                |(query_type_name, mutation_type_name, directive)| SchemaDefinition {
+                    query: query_type_name.to_owned(),
+                    mutation: mutation_type_name.map(|x| x.to_owned()),
+                    directives: vec![directive],
+                },
+            )
     })
 }
diff --git a/src/core/config/directives/telemetry.rs b/src/core/config/directives/telemetry.rs
index 108ff2aab3..a5e4658282 100644
--- a/src/core/config/directives/telemetry.rs
+++ b/src/core/config/directives/telemetry.rs
@@ -87,6 +87,8 @@ pub enum TelemetryExporter {
 /// by Tailcall.  By leveraging this directive, developers gain access to
 /// valuable insights into the performance and behavior of their applications.
 pub struct Telemetry {
+    #[serde(with = "serde_yaml_ng::with::singleton_map")]
+    #[schemars(with = "Option<TelemetryExporter>")]
     pub export: Option<TelemetryExporter>,
     /// The list of headers that will be sent as additional attributes to
     /// telemetry exporters Be careful about **leaking sensitive
diff --git a/src/core/config/from_document.rs b/src/core/config/from_document.rs
index 20096936a4..38bba2f9fb 100644
--- a/src/core/config/from_document.rs
+++ b/src/core/config/from_document.rs
@@ -78,6 +78,7 @@ fn process_schema_directives<T: DirectiveCodec + Default>(
     let mut res = Valid::succeed(T::default());
     for directive in schema_definition.directives.iter() {
         if directive.node.name.node.as_ref() == directive_name {
+            tracing::warn!("@{} directive definition in the graphql schema file is deprecated. Please, refer to blog post https://tailcall.run/blog/migrating-to-graphql-configuration-v2/", directive_name);
             res = T::from_directive(&directive.node);
         }
     }
diff --git a/src/core/config/reader.rs b/src/core/config/reader.rs
index 5240e658e8..6463eefc79 100644
--- a/src/core/config/reader.rs
+++ b/src/core/config/reader.rs
@@ -357,7 +357,7 @@ mod reader_tests {
 
         let config = reader
             .read(format!(
-                "{}/examples/jsonplaceholder_script.graphql",
+                "{}/examples/jsonplaceholder_script.yaml",
                 cargo_manifest
             ))
             .await
diff --git a/tailcall-cloudflare/tests/cf_tests.spec.ts b/tailcall-cloudflare/tests/cf_tests.spec.ts
index fa6812bbfb..00afc6da02 100644
--- a/tailcall-cloudflare/tests/cf_tests.spec.ts
+++ b/tailcall-cloudflare/tests/cf_tests.spec.ts
@@ -4,23 +4,28 @@ import {mf} from "./mf"
 
 describe("fetch", () => {
   test("loadfiles", async () => {
-    let placeholder = (await readFile("../examples/jsonplaceholder.graphql")).toString()
-    let placeholder_batch = (await readFile("../examples/jsonplaceholder_batch.graphql")).toString()
-    let grpc = (await readFile("../examples/grpc.graphql")).toString()
+    let placeholder = (await readFile("../examples/jsonplaceholder.yaml")).toString()
+    let placeholder_schema = (await readFile("../examples/jsonplaceholder.graphql")).toString()
+    let placeholder_batch = (await readFile("../examples/jsonplaceholder_batch.yaml")).toString()
+    let placeholder_batch_schema = (await readFile("../examples/jsonplaceholder_batch.graphql")).toString()
+    let grpc = (await readFile("../examples/grpc.yaml")).toString()
+    let grpc_schema = (await readFile("../examples/grpc.graphql")).toString()
     let news_proto = (await readFile("../tailcall-fixtures/fixtures/protobuf/news.proto")).toString()
     let news_dto_proto = (await readFile("../tailcall-fixtures/fixtures/protobuf/news_dto.proto")).toString()
 
     let bucket = await mf.getR2Bucket("MY_R2")
-    await bucket.put("examples/grpc.graphql", grpc)
+    await bucket.put("examples/grpc.graphql", grpc_schema)
+    await bucket.put("examples/grpc.yaml", grpc)
     await bucket.put("examples/../tailcall-fixtures/fixtures/protobuf/news.proto", news_proto)
     await bucket.put("examples/../tailcall-fixtures/fixtures/protobuf/news_dto.proto", news_dto_proto)
-    await bucket.put("tailcall-fixtures/fixtures/protobuf/news.proto", grpc)
-    await bucket.put("examples/jsonplaceholder.graphql", placeholder)
-    await bucket.put("examples/jsonplaceholder_batch.graphql", placeholder_batch)
+    await bucket.put("examples/jsonplaceholder.graphql", placeholder_schema)
+    await bucket.put("examples/jsonplaceholder.yaml", placeholder)
+    await bucket.put("examples/jsonplaceholder_batch.graphql", placeholder_batch_schema)
+    await bucket.put("examples/jsonplaceholder_batch.yaml", placeholder_batch)
   })
 
   test("sample_resp", async () => {
-    let resp = await mf.dispatchFetch("https://fake.host/graphql?config=examples/jsonplaceholder.graphql", {
+    let resp = await mf.dispatchFetch("https://fake.host/graphql?config=examples/jsonplaceholder.yaml", {
       method: "POST",
       body: '{"query":"{user(id: 1) {id}}"}',
     })
@@ -31,7 +36,7 @@ describe("fetch", () => {
   })
 
   test("test_batching", async () => {
-    let resp = await mf.dispatchFetch("https://fake.host/graphql?config=examples/jsonplaceholder_batch.graphql", {
+    let resp = await mf.dispatchFetch("https://fake.host/graphql?config=examples/jsonplaceholder_batch.yaml", {
       method: "POST",
       body: '{"query":"{ posts { id } }"}',
     })
@@ -42,7 +47,7 @@ describe("fetch", () => {
   })
 
   test("test_grpc", async () => {
-    let resp = await mf.dispatchFetch("https://fake.host/graphql?config=examples/grpc.graphql", {
+    let resp = await mf.dispatchFetch("https://fake.host/graphql?config=examples/grpc.yaml", {
       method: "POST",
       body: '{"query":"{ news { news { id } } }"}',
     })
diff --git a/tests/core/snapshots/grpc-simple.md_client.snap b/tests/core/snapshots/grpc-simple.md_client.snap
index 2fd977b45a..e25e69cac9 100644
--- a/tests/core/snapshots/grpc-simple.md_client.snap
+++ b/tests/core/snapshots/grpc-simple.md_client.snap
@@ -38,4 +38,5 @@ type Query {
 
 schema {
   query: Query
+  mutation: Mutation
 }