diff --git a/frontend/src/metabase-lib/order_by.ts b/frontend/src/metabase-lib/order_by.ts
index cad71031d30aba4986acdde503527e2d12e3d2e2..de2d8d5a809a01b5b8a235460fe3fc3766791cca 100644
--- a/frontend/src/metabase-lib/order_by.ts
+++ b/frontend/src/metabase-lib/order_by.ts
@@ -19,3 +19,11 @@ declare function OrderByFn(
 ): Query;
 
 export const orderBy: typeof OrderByFn = ML.order_by;
+
+export function orderByClause(
+  query: Query,
+  stageNumber: number,
+  field: Field,
+): Field {
+  return ML.order_by_clause(query, stageNumber, field);
+}
diff --git a/frontend/src/metabase-lib/order_by.unit.spec.ts b/frontend/src/metabase-lib/order_by.unit.spec.ts
index 7dc1a0905e023a570ef127546b5364cd7e9d38c2..467fcb2a38499f127b55f6b0b556c0223e86968d 100644
--- a/frontend/src/metabase-lib/order_by.unit.spec.ts
+++ b/frontend/src/metabase-lib/order_by.unit.spec.ts
@@ -59,4 +59,51 @@ describe("order by", () => {
       expect(ML.displayName(nextQuery, orderBys[0])).toBe("Title ascending");
     });
   });
+
+  describe("replace order by", () => {
+    const query = createQuery();
+
+    it("should update the query", () => {
+      const columns = ML.orderableColumns(query);
+      const productTitle = columns.find(
+        column => column.id === SAMPLE_DATABASE.PRODUCTS.TITLE.id,
+      );
+
+      const productCategory = columns.find(
+        column => column.id === SAMPLE_DATABASE.PRODUCTS.CATEGORY.id,
+      );
+      const orderedQuery = ML.orderBy(query, productTitle as Field);
+      const orderBys = ML.orderBys(orderedQuery);
+
+      expect(orderBys).toHaveLength(1);
+      const nextQuery = ML.replaceClause(
+        orderedQuery,
+        orderBys[0],
+        ML.orderByClause(orderedQuery, -1, productCategory as Field) as Field,
+      );
+      const nextOrderBys = ML.orderBys(nextQuery);
+      expect(ML.displayName(nextQuery, nextOrderBys[0])).toBe(
+        "Category ascending",
+      );
+      expect(orderBys[0]).not.toEqual(nextOrderBys[0]);
+    });
+  });
+
+  describe("remove order by", () => {
+    const query = createQuery();
+
+    it("should update the query", () => {
+      const columns = ML.orderableColumns(query);
+      const productTitle = columns.find(
+        column => column.id === SAMPLE_DATABASE.PRODUCTS.TITLE.id,
+      );
+
+      const orderedQuery = ML.orderBy(query, productTitle as Field);
+      const orderBys = ML.orderBys(orderedQuery);
+      expect(orderBys).toHaveLength(1);
+
+      const nextQuery = ML.removeClause(orderedQuery, orderBys[0]);
+      expect(ML.orderBys(nextQuery)).toHaveLength(0);
+    });
+  });
 });
diff --git a/frontend/src/metabase-lib/query.ts b/frontend/src/metabase-lib/query.ts
index d8bb3b3a2690df1992e70b6e9a36f299bdc88232..824dbd687e95b23045696406073507c980a5928c 100644
--- a/frontend/src/metabase-lib/query.ts
+++ b/frontend/src/metabase-lib/query.ts
@@ -1,6 +1,6 @@
 import * as ML from "cljs/metabase.lib.js";
-import type { DatabaseId, DatasetQuery } from "metabase-types/api";
-import type { MetadataProvider, Query } from "./types";
+import type { DatabaseId, DatasetQuery, Field } from "metabase-types/api";
+import type { Clause, MetadataProvider, Query } from "./types";
 
 export function fromLegacyQuery(
   databaseId: DatabaseId,
@@ -17,3 +17,26 @@ export function toLegacyQuery(query: Query): DatasetQuery {
 export function suggestedName(query: Query): string {
   return ML.suggestedName(query);
 }
+
+declare function RemoveClauseFn(query: Query, targetClause: Clause): Query;
+declare function RemoveClauseFn(
+  query: Query,
+  stageIndex: number,
+  targetClause: Clause,
+): Query;
+
+export const removeClause: typeof RemoveClauseFn = ML.remove_clause;
+
+declare function ReplaceClauseFn(
+  query: Query,
+  targetClause: Clause,
+  newClause: Field,
+): Query;
+declare function ReplaceClauseFn(
+  query: Query,
+  stageIndex: number,
+  targetClause: Clause,
+  newClause: Field,
+): Query;
+
+export const replaceClause: typeof ReplaceClauseFn = ML.replace_clause;
diff --git a/src/metabase/lib/js.cljs b/src/metabase/lib/js.cljs
index 3598fd6689f47d4e6ccd6f5c915ed224664e4626..782917d771fea68ed87b5abecb9767b71be15bf6 100644
--- a/src/metabase/lib/js.cljs
+++ b/src/metabase/lib/js.cljs
@@ -104,6 +104,11 @@
    (-> (lib.order-by/orderable-columns a-query stage-number)
        (clj->js :keyword-fn u/qualified-name))))
 
+(defn ^:export order-by-clause
+  "Create an order-by clause independently of a query, e.g. for `replace` or whatever."
+  [a-query stage-number x]
+  (lib.order-by/order-by-clause a-query stage-number (lib.normalize/normalize (js->clj x :keywordize-keys true))))
+
 (defn ^:export order-by
   "Add an `order-by` clause to `a-query`. Returns updated query."
   ([a-query x]
@@ -128,3 +133,22 @@
    (some-> (lib.order-by/order-bys a-query stage-number)
            not-empty
            to-array)))
+
+(defn ^:export remove-clause
+  "Removes the `target-clause` in the filter of the `query`."
+  ([a-query clause]
+   (remove-clause a-query -1 clause))
+  ([a-query stage-number clause]
+   (lib.query/remove-clause
+     a-query stage-number
+     (lib.normalize/normalize (js->clj clause :keywordize-keys true)))))
+
+(defn ^:export replace-clause
+  "Replaces the `target-clause` with `new-clause` in the `query` stage."
+  ([a-query target-clause new-clause]
+   (replace-clause a-query -1 target-clause new-clause))
+  ([a-query stage-number target-clause new-clause]
+   (lib.query/replace-clause
+     a-query stage-number
+     (lib.normalize/normalize (js->clj target-clause :keywordize-keys true))
+     (lib.normalize/normalize (js->clj new-clause :keywordize-keys true)))))
diff --git a/src/metabase/lib/order_by.cljc b/src/metabase/lib/order_by.cljc
index d65decbde0eb42048fd5ffba2640e486a8199077..fdb8618045ed80d7d9949f7fd07c16367b33444a 100644
--- a/src/metabase/lib/order_by.cljc
+++ b/src/metabase/lib/order_by.cljc
@@ -90,7 +90,7 @@
      (lib.util/update-query-stage query stage-number update :order-by (fn [order-bys]
                                                                         (conj (vec order-bys) new-order-by))))))
 
-(mu/defn ^:export order-bys :- [:maybe [:sequential ::lib.schema.order-by/order-by]]
+(mu/defn order-bys :- [:maybe [:sequential ::lib.schema.order-by/order-by]]
   "Get the order-by clauses in a query."
   ([query :- ::lib.schema/query]
    (order-bys query -1))
diff --git a/src/metabase/lib/query.cljc b/src/metabase/lib/query.cljc
index 9604659e98137383d3bb3d009b0535c634e84162..778a5a75aedd288b1b6c42c1316778075023871f 100644
--- a/src/metabase/lib/query.cljc
+++ b/src/metabase/lib/query.cljc
@@ -14,7 +14,7 @@
    [metabase.util.malli :as mu]))
 
 (mu/defn replace-clause :- :metabase.lib.schema/query
-  "Replaces the `target-clause` with `new-clase` in the `query` stage."
+  "Replaces the `target-clause` with `new-clause` in the `query` stage."
   ([query :- :metabase.lib.schema/query
     target-clause
     new-clause]