In my opinion nothing prevents you from using community detection algorithms such as Louvain or Leiden for clustering, even though you have a small amount of cells.
Since these algorithms take a graph as an input, which for pipelines implemented in Seurat and similar workflows is constructed as a SNN (Shared Nearest Neighbour) graph, you may want to reduce the number of neighbours required to draw an edge. A KNN graph will have similar caveats.
If you are working with R, the bluster
(Biocondcutor) and igraph
(CRAN) packages have all the functions you need for this.
(edit to add: since you are working with very small numbers of cells, a hierarchical clustering on the distance matrix in PCA space would work just as well, and allow you to choose different levels of resolution.)
The problematic part concerns the validity of differential expression between conditions without biological replicates. If your cells come from a single individual or experiment then using them as replicates - which is what the FindMarkers()
function does, applying a test from a number of possibilities - is not ideal, as they are not actually biological/experimental replicates. This can work in principle for "marker gene" detection, but it becomes less valid for modelling the effect of treatments at the cluster level (or at any level).
If instead you have replicates, I recommend aggregating cells within each cluster and using methods developed for bulk RNA-seq differential expression such as the ones implemented in DESeq2
or edgeR
. You can read more about this approach here.